]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/inline/inl.go
[dev.typeparams] all: merge dev.regabi (7e0a81d) 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 30
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 -= 30
368
369         case ir.ORANGE,
370                 ir.OSELECT,
371                 ir.OGO,
372                 ir.ODEFER,
373                 ir.ODCLTYPE, // can't print yet
374                 ir.OTAILCALL:
375                 v.reason = "unhandled op " + n.Op().String()
376                 return true
377
378         case ir.OAPPEND:
379                 v.budget -= inlineExtraAppendCost
380
381         case ir.ODCLCONST, ir.OFALL:
382                 // These nodes don't produce code; omit from inlining budget.
383                 return false
384
385         case ir.OFOR, ir.OFORUNTIL:
386                 n := n.(*ir.ForStmt)
387                 if n.Label != nil {
388                         v.reason = "labeled control"
389                         return true
390                 }
391         case ir.OSWITCH:
392                 n := n.(*ir.SwitchStmt)
393                 if n.Label != nil {
394                         v.reason = "labeled control"
395                         return true
396                 }
397         // case ir.ORANGE, ir.OSELECT in "unhandled" above
398
399         case ir.OBREAK, ir.OCONTINUE:
400                 n := n.(*ir.BranchStmt)
401                 if n.Label != nil {
402                         // Should have short-circuited due to labeled control error above.
403                         base.Fatalf("unexpected labeled break/continue: %v", n)
404                 }
405
406         case ir.OIF:
407                 n := n.(*ir.IfStmt)
408                 if ir.IsConst(n.Cond, constant.Bool) {
409                         // This if and the condition cost nothing.
410                         // TODO(rsc): It seems strange that we visit the dead branch.
411                         return doList(n.Init(), v.do) ||
412                                 doList(n.Body, v.do) ||
413                                 doList(n.Else, v.do)
414                 }
415
416         case ir.ONAME:
417                 n := n.(*ir.Name)
418                 if n.Class == ir.PAUTO {
419                         v.usedLocals.Add(n)
420                 }
421
422         case ir.OBLOCK:
423                 // The only OBLOCK we should see at this point is an empty one.
424                 // In any event, let the visitList(n.List()) below take care of the statements,
425                 // and don't charge for the OBLOCK itself. The ++ undoes the -- below.
426                 v.budget++
427
428         case ir.OCALLPART, ir.OSLICELIT:
429                 v.budget-- // Hack for toolstash -cmp.
430
431         case ir.OMETHEXPR:
432                 v.budget++ // Hack for toolstash -cmp.
433         }
434
435         v.budget--
436
437         // When debugging, don't stop early, to get full cost of inlining this function
438         if v.budget < 0 && base.Flag.LowerM < 2 && !logopt.Enabled() {
439                 v.reason = "too expensive"
440                 return true
441         }
442
443         return ir.DoChildren(n, v.do)
444 }
445
446 func isBigFunc(fn *ir.Func) bool {
447         budget := inlineBigFunctionNodes
448         return ir.Any(fn, func(n ir.Node) bool {
449                 budget--
450                 return budget <= 0
451         })
452 }
453
454 // inlcopylist (together with inlcopy) recursively copies a list of nodes, except
455 // that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
456 // the body and dcls of an inlineable function.
457 func inlcopylist(ll []ir.Node) []ir.Node {
458         s := make([]ir.Node, len(ll))
459         for i, n := range ll {
460                 s[i] = inlcopy(n)
461         }
462         return s
463 }
464
465 // inlcopy is like DeepCopy(), but does extra work to copy closures.
466 func inlcopy(n ir.Node) ir.Node {
467         var edit func(ir.Node) ir.Node
468         edit = func(x ir.Node) ir.Node {
469                 switch x.Op() {
470                 case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
471                         return x
472                 }
473                 m := ir.Copy(x)
474                 ir.EditChildren(m, edit)
475                 if x.Op() == ir.OCLOSURE {
476                         x := x.(*ir.ClosureExpr)
477                         // Need to save/duplicate x.Func.Nname,
478                         // x.Func.Nname.Ntype, x.Func.Dcl, x.Func.ClosureVars, and
479                         // x.Func.Body for iexport and local inlining.
480                         oldfn := x.Func
481                         newfn := ir.NewFunc(oldfn.Pos())
482                         if oldfn.ClosureCalled() {
483                                 newfn.SetClosureCalled(true)
484                         }
485                         m.(*ir.ClosureExpr).Func = newfn
486                         newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym())
487                         // XXX OK to share fn.Type() ??
488                         newfn.Nname.SetType(oldfn.Nname.Type())
489                         newfn.Nname.Ntype = inlcopy(oldfn.Nname.Ntype).(ir.Ntype)
490                         newfn.Body = inlcopylist(oldfn.Body)
491                         // Make shallow copy of the Dcl and ClosureVar slices
492                         newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...)
493                         newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...)
494                 }
495                 return m
496         }
497         return edit(n)
498 }
499
500 // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
501 // calls made to inlineable functions. This is the external entry point.
502 func InlineCalls(fn *ir.Func) {
503         savefn := ir.CurFunc
504         ir.CurFunc = fn
505         maxCost := int32(inlineMaxBudget)
506         if isBigFunc(fn) {
507                 maxCost = inlineBigFunctionMaxCost
508         }
509         // Map to keep track of functions that have been inlined at a particular
510         // call site, in order to stop inlining when we reach the beginning of a
511         // recursion cycle again. We don't inline immediately recursive functions,
512         // but allow inlining if there is a recursion cycle of many functions.
513         // Most likely, the inlining will stop before we even hit the beginning of
514         // the cycle again, but the map catches the unusual case.
515         inlMap := make(map[*ir.Func]bool)
516         var edit func(ir.Node) ir.Node
517         edit = func(n ir.Node) ir.Node {
518                 return inlnode(n, maxCost, inlMap, edit)
519         }
520         ir.EditChildren(fn, edit)
521         ir.CurFunc = savefn
522 }
523
524 // Turn an OINLCALL into a statement.
525 func inlconv2stmt(inlcall *ir.InlinedCallExpr) ir.Node {
526         n := ir.NewBlockStmt(inlcall.Pos(), nil)
527         n.List = inlcall.Init()
528         n.List.Append(inlcall.Body.Take()...)
529         return n
530 }
531
532 // Turn an OINLCALL into a single valued expression.
533 // The result of inlconv2expr MUST be assigned back to n, e.g.
534 //      n.Left = inlconv2expr(n.Left)
535 func inlconv2expr(n *ir.InlinedCallExpr) ir.Node {
536         r := n.ReturnVars[0]
537         return ir.InitExpr(append(n.Init(), n.Body...), r)
538 }
539
540 // Turn the rlist (with the return values) of the OINLCALL in
541 // n into an expression list lumping the ninit and body
542 // containing the inlined statements on the first list element so
543 // order will be preserved. Used in return, oas2func and call
544 // statements.
545 func inlconv2list(n *ir.InlinedCallExpr) []ir.Node {
546         if n.Op() != ir.OINLCALL || len(n.ReturnVars) == 0 {
547                 base.Fatalf("inlconv2list %+v\n", n)
548         }
549
550         s := n.ReturnVars
551         s[0] = ir.InitExpr(append(n.Init(), n.Body...), s[0])
552         return s
553 }
554
555 // inlnode recurses over the tree to find inlineable calls, which will
556 // be turned into OINLCALLs by mkinlcall. When the recursion comes
557 // back up will examine left, right, list, rlist, ninit, ntest, nincr,
558 // nbody and nelse and use one of the 4 inlconv/glue functions above
559 // to turn the OINLCALL into an expression, a statement, or patch it
560 // in to this nodes list or rlist as appropriate.
561 // NOTE it makes no sense to pass the glue functions down the
562 // recursion to the level where the OINLCALL gets created because they
563 // have to edit /this/ n, so you'd have to push that one down as well,
564 // but then you may as well do it here.  so this is cleaner and
565 // shorter and less complicated.
566 // The result of inlnode MUST be assigned back to n, e.g.
567 //      n.Left = inlnode(n.Left)
568 func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
569         if n == nil {
570                 return n
571         }
572
573         switch n.Op() {
574         case ir.ODEFER, ir.OGO:
575                 n := n.(*ir.GoDeferStmt)
576                 switch call := n.Call; call.Op() {
577                 case ir.OCALLFUNC, ir.OCALLMETH:
578                         call := call.(*ir.CallExpr)
579                         call.NoInline = true
580                 }
581
582         // TODO do them here (or earlier),
583         // so escape analysis can avoid more heapmoves.
584         case ir.OCLOSURE:
585                 return n
586         case ir.OCALLMETH:
587                 // Prevent inlining some reflect.Value methods when using checkptr,
588                 // even when package reflect was compiled without it (#35073).
589                 n := n.(*ir.CallExpr)
590                 if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
591                         return n
592                 }
593         }
594
595         lno := ir.SetPos(n)
596
597         ir.EditChildren(n, edit)
598
599         if as := n; as.Op() == ir.OAS2FUNC {
600                 as := as.(*ir.AssignListStmt)
601                 if as.Rhs[0].Op() == ir.OINLCALL {
602                         as.Rhs = inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr))
603                         as.SetOp(ir.OAS2)
604                         as.SetTypecheck(0)
605                         n = typecheck.Stmt(as)
606                 }
607         }
608
609         // with all the branches out of the way, it is now time to
610         // transmogrify this node itself unless inhibited by the
611         // switch at the top of this function.
612         switch n.Op() {
613         case ir.OCALLFUNC, ir.OCALLMETH:
614                 n := n.(*ir.CallExpr)
615                 if n.NoInline {
616                         return n
617                 }
618         }
619
620         var call *ir.CallExpr
621         switch n.Op() {
622         case ir.OCALLFUNC:
623                 call = n.(*ir.CallExpr)
624                 if base.Flag.LowerM > 3 {
625                         fmt.Printf("%v:call to func %+v\n", ir.Line(n), call.X)
626                 }
627                 if ir.IsIntrinsicCall(call) {
628                         break
629                 }
630                 if fn := inlCallee(call.X); fn != nil && fn.Inl != nil {
631                         n = mkinlcall(call, fn, maxCost, inlMap, edit)
632                 }
633
634         case ir.OCALLMETH:
635                 call = n.(*ir.CallExpr)
636                 if base.Flag.LowerM > 3 {
637                         fmt.Printf("%v:call to meth %v\n", ir.Line(n), call.X.(*ir.SelectorExpr).Sel)
638                 }
639
640                 // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
641                 if call.X.Type() == nil {
642                         base.Fatalf("no function type for [%p] %+v\n", call.X, call.X)
643                 }
644
645                 n = mkinlcall(call, ir.MethodExprName(call.X).Func, maxCost, inlMap, edit)
646         }
647
648         base.Pos = lno
649
650         if n.Op() == ir.OINLCALL {
651                 ic := n.(*ir.InlinedCallExpr)
652                 switch call.Use {
653                 default:
654                         ir.Dump("call", call)
655                         base.Fatalf("call missing use")
656                 case ir.CallUseExpr:
657                         n = inlconv2expr(ic)
658                 case ir.CallUseStmt:
659                         n = inlconv2stmt(ic)
660                 case ir.CallUseList:
661                         // leave for caller to convert
662                 }
663         }
664
665         return n
666 }
667
668 // inlCallee takes a function-typed expression and returns the underlying function ONAME
669 // that it refers to if statically known. Otherwise, it returns nil.
670 func inlCallee(fn ir.Node) *ir.Func {
671         fn = ir.StaticValue(fn)
672         switch fn.Op() {
673         case ir.OMETHEXPR:
674                 fn := fn.(*ir.SelectorExpr)
675                 n := ir.MethodExprName(fn)
676                 // Check that receiver type matches fn.X.
677                 // TODO(mdempsky): Handle implicit dereference
678                 // of pointer receiver argument?
679                 if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
680                         return nil
681                 }
682                 return n.Func
683         case ir.ONAME:
684                 fn := fn.(*ir.Name)
685                 if fn.Class == ir.PFUNC {
686                         return fn.Func
687                 }
688         case ir.OCLOSURE:
689                 fn := fn.(*ir.ClosureExpr)
690                 c := fn.Func
691                 CanInline(c)
692                 return c
693         }
694         return nil
695 }
696
697 func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
698         if t.Nname == nil {
699                 return ir.BlankNode
700         }
701         n := t.Nname.(*ir.Name)
702         if ir.IsBlank(n) {
703                 return ir.BlankNode
704         }
705         inlvar := inlvars[n]
706         if inlvar == nil {
707                 base.Fatalf("missing inlvar for %v", n)
708         }
709         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
710         inlvar.Name().Defn = as
711         return inlvar
712 }
713
714 var inlgen int
715
716 // SSADumpInline gives the SSA back end a chance to dump the function
717 // when producing output for debugging the compiler itself.
718 var SSADumpInline = func(*ir.Func) {}
719
720 // If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
721 // function with an inlinable body, return an OINLCALL node that can replace n.
722 // The returned node's Ninit has the parameter assignments, the Nbody is the
723 // inlined function body, and (List, Rlist) contain the (input, output)
724 // parameters.
725 // The result of mkinlcall MUST be assigned back to n, e.g.
726 //      n.Left = mkinlcall(n.Left, fn, isddd)
727 func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
728         if fn.Inl == nil {
729                 if logopt.Enabled() {
730                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
731                                 fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
732                 }
733                 return n
734         }
735         if fn.Inl.Cost > maxCost {
736                 // The inlined function body is too big. Typically we use this check to restrict
737                 // inlining into very big functions.  See issue 26546 and 17566.
738                 if logopt.Enabled() {
739                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
740                                 fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), maxCost))
741                 }
742                 return n
743         }
744
745         if fn == ir.CurFunc {
746                 // Can't recursively inline a function into itself.
747                 if logopt.Enabled() {
748                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(ir.CurFunc)))
749                 }
750                 return n
751         }
752
753         if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
754                 // Runtime package must not be instrumented.
755                 // Instrument skips runtime package. However, some runtime code can be
756                 // inlined into other packages and instrumented there. To avoid this,
757                 // we disable inlining of runtime functions when instrumenting.
758                 // The example that we observed is inlining of LockOSThread,
759                 // which lead to false race reports on m contents.
760                 return n
761         }
762
763         if inlMap[fn] {
764                 if base.Flag.LowerM > 1 {
765                         fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", ir.Line(n), fn, ir.FuncName(ir.CurFunc))
766                 }
767                 return n
768         }
769         inlMap[fn] = true
770         defer func() {
771                 inlMap[fn] = false
772         }()
773         if base.Debug.TypecheckInl == 0 {
774                 typecheck.ImportedBody(fn)
775         }
776
777         // We have a function node, and it has an inlineable body.
778         if base.Flag.LowerM > 1 {
779                 fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.Nodes(fn.Inl.Body))
780         } else if base.Flag.LowerM != 0 {
781                 fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
782         }
783         if base.Flag.LowerM > 2 {
784                 fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
785         }
786
787         SSADumpInline(fn)
788
789         ninit := n.Init()
790
791         // For normal function calls, the function callee expression
792         // may contain side effects (e.g., added by addinit during
793         // inlconv2expr or inlconv2list). Make sure to preserve these,
794         // if necessary (#42703).
795         if n.Op() == ir.OCALLFUNC {
796                 callee := n.X
797                 for callee.Op() == ir.OCONVNOP {
798                         conv := callee.(*ir.ConvExpr)
799                         ninit.Append(ir.TakeInit(conv)...)
800                         callee = conv.X
801                 }
802                 if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
803                         base.Fatalf("unexpected callee expression: %v", callee)
804                 }
805         }
806
807         // Make temp names to use instead of the originals.
808         inlvars := make(map[*ir.Name]*ir.Name)
809
810         // record formals/locals for later post-processing
811         var inlfvars []*ir.Name
812
813         for _, ln := range fn.Inl.Dcl {
814                 if ln.Op() != ir.ONAME {
815                         continue
816                 }
817                 if ln.Class == ir.PPARAMOUT { // return values handled below.
818                         continue
819                 }
820                 inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
821                 inlvars[ln] = inlf
822                 if base.Flag.GenDwarfInl > 0 {
823                         if ln.Class == ir.PPARAM {
824                                 inlf.Name().SetInlFormal(true)
825                         } else {
826                                 inlf.Name().SetInlLocal(true)
827                         }
828                         inlf.SetPos(ln.Pos())
829                         inlfvars = append(inlfvars, inlf)
830                 }
831         }
832
833         nreturns := 0
834         ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
835                 if n != nil && n.Op() == ir.ORETURN {
836                         nreturns++
837                 }
838         })
839
840         // We can delay declaring+initializing result parameters if:
841         // (1) there's only one "return" statement in the inlined
842         // function, and (2) the result parameters aren't named.
843         delayretvars := nreturns == 1
844
845         // temporaries for return values.
846         var retvars []ir.Node
847         for i, t := range fn.Type().Results().Fields().Slice() {
848                 var m *ir.Name
849                 if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
850                         n := nn.(*ir.Name)
851                         m = inlvar(n)
852                         m = typecheck.Expr(m).(*ir.Name)
853                         inlvars[n] = m
854                         delayretvars = false // found a named result parameter
855                 } else {
856                         // anonymous return values, synthesize names for use in assignment that replaces return
857                         m = retvar(t, i)
858                 }
859
860                 if base.Flag.GenDwarfInl > 0 {
861                         // Don't update the src.Pos on a return variable if it
862                         // was manufactured by the inliner (e.g. "~R2"); such vars
863                         // were not part of the original callee.
864                         if !strings.HasPrefix(m.Sym().Name, "~R") {
865                                 m.Name().SetInlFormal(true)
866                                 m.SetPos(t.Pos)
867                                 inlfvars = append(inlfvars, m)
868                         }
869                 }
870
871                 retvars = append(retvars, m)
872         }
873
874         // Assign arguments to the parameters' temp names.
875         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
876         as.Def = true
877         if n.Op() == ir.OCALLMETH {
878                 sel := n.X.(*ir.SelectorExpr)
879                 if sel.X == nil {
880                         base.Fatalf("method call without receiver: %+v", n)
881                 }
882                 as.Rhs.Append(sel.X)
883         }
884         as.Rhs.Append(n.Args...)
885
886         // For non-dotted calls to variadic functions, we assign the
887         // variadic parameter's temp name separately.
888         var vas *ir.AssignStmt
889
890         if recv := fn.Type().Recv(); recv != nil {
891                 as.Lhs.Append(inlParam(recv, as, inlvars))
892         }
893         for _, param := range fn.Type().Params().Fields().Slice() {
894                 // For ordinary parameters or variadic parameters in
895                 // dotted calls, just add the variable to the
896                 // assignment list, and we're done.
897                 if !param.IsDDD() || n.IsDDD {
898                         as.Lhs.Append(inlParam(param, as, inlvars))
899                         continue
900                 }
901
902                 // Otherwise, we need to collect the remaining values
903                 // to pass as a slice.
904
905                 x := len(as.Lhs)
906                 for len(as.Lhs) < len(as.Rhs) {
907                         as.Lhs.Append(argvar(param.Type, len(as.Lhs)))
908                 }
909                 varargs := as.Lhs[x:]
910
911                 vas = ir.NewAssignStmt(base.Pos, nil, nil)
912                 vas.X = inlParam(param, vas, inlvars)
913                 if len(varargs) == 0 {
914                         vas.Y = typecheck.NodNil()
915                         vas.Y.SetType(param.Type)
916                 } else {
917                         lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil)
918                         lit.List = varargs
919                         vas.Y = lit
920                 }
921         }
922
923         if len(as.Rhs) != 0 {
924                 ninit.Append(typecheck.Stmt(as))
925         }
926
927         if vas != nil {
928                 ninit.Append(typecheck.Stmt(vas))
929         }
930
931         if !delayretvars {
932                 // Zero the return parameters.
933                 for _, n := range retvars {
934                         ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
935                         ras := ir.NewAssignStmt(base.Pos, n, nil)
936                         ninit.Append(typecheck.Stmt(ras))
937                 }
938         }
939
940         retlabel := typecheck.AutoLabel(".i")
941
942         inlgen++
943
944         parent := -1
945         if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil {
946                 parent = b.InliningIndex()
947         }
948
949         sym := fn.Linksym()
950         newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
951
952         // Add an inline mark just before the inlined body.
953         // This mark is inline in the code so that it's a reasonable spot
954         // to put a breakpoint. Not sure if that's really necessary or not
955         // (in which case it could go at the end of the function instead).
956         // Note issue 28603.
957         inlMark := ir.NewInlineMarkStmt(base.Pos, types.BADWIDTH)
958         inlMark.SetPos(n.Pos().WithIsStmt())
959         inlMark.Index = int64(newIndex)
960         ninit.Append(inlMark)
961
962         if base.Flag.GenDwarfInl > 0 {
963                 if !sym.WasInlined() {
964                         base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn)
965                         sym.Set(obj.AttrWasInlined, true)
966                 }
967         }
968
969         subst := inlsubst{
970                 retlabel:     retlabel,
971                 retvars:      retvars,
972                 delayretvars: delayretvars,
973                 inlvars:      inlvars,
974                 bases:        make(map[*src.PosBase]*src.PosBase),
975                 newInlIndex:  newIndex,
976                 fn:           fn,
977         }
978         subst.edit = subst.node
979
980         body := subst.list(ir.Nodes(fn.Inl.Body))
981
982         lab := ir.NewLabelStmt(base.Pos, retlabel)
983         body = append(body, lab)
984
985         typecheck.Stmts(body)
986
987         if base.Flag.GenDwarfInl > 0 {
988                 for _, v := range inlfvars {
989                         v.SetPos(subst.updatedPos(v.Pos()))
990                 }
991         }
992
993         //dumplist("ninit post", ninit);
994
995         call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
996         *call.PtrInit() = ninit
997         call.Body = body
998         call.ReturnVars = retvars
999         call.SetType(n.Type())
1000         call.SetTypecheck(1)
1001
1002         // transitive inlining
1003         // might be nice to do this before exporting the body,
1004         // but can't emit the body with inlining expanded.
1005         // instead we emit the things that the body needs
1006         // and each use must redo the inlining.
1007         // luckily these are small.
1008         ir.EditChildren(call, edit)
1009
1010         if base.Flag.LowerM > 2 {
1011                 fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
1012         }
1013
1014         return call
1015 }
1016
1017 // Every time we expand a function we generate a new set of tmpnames,
1018 // PAUTO's in the calling functions, and link them off of the
1019 // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
1020 func inlvar(var_ *ir.Name) *ir.Name {
1021         if base.Flag.LowerM > 3 {
1022                 fmt.Printf("inlvar %+v\n", var_)
1023         }
1024
1025         n := typecheck.NewName(var_.Sym())
1026         n.SetType(var_.Type())
1027         n.Class = ir.PAUTO
1028         n.SetUsed(true)
1029         n.Curfn = ir.CurFunc // the calling function, not the called one
1030         n.SetAddrtaken(var_.Addrtaken())
1031
1032         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1033         return n
1034 }
1035
1036 // Synthesize a variable to store the inlined function's results in.
1037 func retvar(t *types.Field, i int) *ir.Name {
1038         n := typecheck.NewName(typecheck.LookupNum("~R", i))
1039         n.SetType(t.Type)
1040         n.Class = ir.PAUTO
1041         n.SetUsed(true)
1042         n.Curfn = ir.CurFunc // the calling function, not the called one
1043         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1044         return n
1045 }
1046
1047 // Synthesize a variable to store the inlined function's arguments
1048 // when they come from a multiple return call.
1049 func argvar(t *types.Type, i int) ir.Node {
1050         n := typecheck.NewName(typecheck.LookupNum("~arg", i))
1051         n.SetType(t.Elem())
1052         n.Class = ir.PAUTO
1053         n.SetUsed(true)
1054         n.Curfn = ir.CurFunc // the calling function, not the called one
1055         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1056         return n
1057 }
1058
1059 // The inlsubst type implements the actual inlining of a single
1060 // function call.
1061 type inlsubst struct {
1062         // Target of the goto substituted in place of a return.
1063         retlabel *types.Sym
1064
1065         // Temporary result variables.
1066         retvars []ir.Node
1067
1068         // Whether result variables should be initialized at the
1069         // "return" statement.
1070         delayretvars bool
1071
1072         inlvars map[*ir.Name]*ir.Name
1073
1074         // bases maps from original PosBase to PosBase with an extra
1075         // inlined call frame.
1076         bases map[*src.PosBase]*src.PosBase
1077
1078         // newInlIndex is the index of the inlined call frame to
1079         // insert for inlined nodes.
1080         newInlIndex int
1081
1082         edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
1083
1084         // If non-nil, we are inside a closure inside the inlined function, and
1085         // newclofn is the Func of the new inlined closure.
1086         newclofn *ir.Func
1087
1088         fn *ir.Func // For debug -- the func that is being inlined
1089 }
1090
1091 // list inlines a list of nodes.
1092 func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
1093         s := make([]ir.Node, 0, len(ll))
1094         for _, n := range ll {
1095                 s = append(s, subst.node(n))
1096         }
1097         return s
1098 }
1099
1100 // fields returns a list of the fields of a struct type representing receiver,
1101 // params, or results, after duplicating the field nodes and substituting the
1102 // Nname nodes inside the field nodes.
1103 func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
1104         oldfields := oldt.FieldSlice()
1105         newfields := make([]*types.Field, len(oldfields))
1106         for i := range oldfields {
1107                 newfields[i] = oldfields[i].Copy()
1108                 if oldfields[i].Nname != nil {
1109                         newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
1110                 }
1111         }
1112         return newfields
1113 }
1114
1115 // clovar creates a new ONAME node for a local variable or param of a closure
1116 // inside a function being inlined.
1117 func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
1118         // TODO(danscales): want to get rid of this shallow copy, with code like the
1119         // following, but it is hard to copy all the necessary flags in a maintainable way.
1120         // m := ir.NewNameAt(n.Pos(), n.Sym())
1121         // m.Class = n.Class
1122         // m.SetType(n.Type())
1123         // m.SetTypecheck(1)
1124         //if n.IsClosureVar() {
1125         //      m.SetIsClosureVar(true)
1126         //}
1127         m := &ir.Name{}
1128         *m = *n
1129         m.Curfn = subst.newclofn
1130         if n.Defn != nil && n.Defn.Op() == ir.ONAME {
1131                 if !n.IsClosureVar() {
1132                         base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
1133                 }
1134                 if n.Sym().Pkg != types.LocalPkg {
1135                         // If the closure came from inlining a function from
1136                         // another package, must change package of captured
1137                         // variable to localpkg, so that the fields of the closure
1138                         // struct are local package and can be accessed even if
1139                         // name is not exported. If you disable this code, you can
1140                         // reproduce the problem by running 'go test
1141                         // go/internal/srcimporter'. TODO(mdempsky) - maybe change
1142                         // how we create closure structs?
1143                         m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
1144                 }
1145                 // Make sure any inlvar which is the Defn
1146                 // of an ONAME closure var is rewritten
1147                 // during inlining. Don't substitute
1148                 // if Defn node is outside inlined function.
1149                 if subst.inlvars[n.Defn.(*ir.Name)] != nil {
1150                         m.Defn = subst.node(n.Defn)
1151                 }
1152         }
1153         if n.Outer != nil {
1154                 // Either the outer variable is defined in function being inlined,
1155                 // and we will replace it with the substituted variable, or it is
1156                 // defined outside the function being inlined, and we should just
1157                 // skip the outer variable (the closure variable of the function
1158                 // being inlined).
1159                 s := subst.node(n.Outer).(*ir.Name)
1160                 if s == n.Outer {
1161                         s = n.Outer.Outer
1162                 }
1163                 m.Outer = s
1164         }
1165         return m
1166 }
1167
1168 // closure does the necessary substitions for a ClosureExpr n and returns the new
1169 // closure node.
1170 func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
1171         m := ir.Copy(n)
1172         m.SetPos(subst.updatedPos(m.Pos()))
1173         ir.EditChildren(m, subst.edit)
1174
1175         //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
1176
1177         // The following is similar to funcLit
1178         oldfn := n.Func
1179         newfn := ir.NewFunc(oldfn.Pos())
1180         // These three lines are not strictly necessary, but just to be clear
1181         // that new function needs to redo typechecking and inlinability.
1182         newfn.SetTypecheck(0)
1183         newfn.SetInlinabilityChecked(false)
1184         newfn.Inl = nil
1185         newfn.SetIsHiddenClosure(true)
1186         newfn.Nname = ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
1187         newfn.Nname.Func = newfn
1188         newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype)
1189         newfn.Nname.Defn = newfn
1190
1191         m.(*ir.ClosureExpr).Func = newfn
1192         newfn.OClosure = m.(*ir.ClosureExpr)
1193
1194         if subst.newclofn != nil {
1195                 //fmt.Printf("Inlining a closure with a nested closure\n")
1196         }
1197         prevxfunc := subst.newclofn
1198
1199         // Mark that we are now substituting within a closure (within the
1200         // inlined function), and create new nodes for all the local
1201         // vars/params inside this closure.
1202         subst.newclofn = newfn
1203         newfn.Dcl = nil
1204         newfn.ClosureVars = nil
1205         for _, oldv := range oldfn.Dcl {
1206                 newv := subst.clovar(oldv)
1207                 subst.inlvars[oldv] = newv
1208                 newfn.Dcl = append(newfn.Dcl, newv)
1209         }
1210         for _, oldv := range oldfn.ClosureVars {
1211                 newv := subst.clovar(oldv)
1212                 subst.inlvars[oldv] = newv
1213                 newfn.ClosureVars = append(newfn.ClosureVars, newv)
1214         }
1215
1216         // Need to replace ONAME nodes in
1217         // newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
1218         oldt := oldfn.Type()
1219         newrecvs := subst.fields(oldt.Recvs())
1220         var newrecv *types.Field
1221         if len(newrecvs) > 0 {
1222                 newrecv = newrecvs[0]
1223         }
1224         newt := types.NewSignature(oldt.Pkg(), newrecv,
1225                 subst.fields(oldt.Params()), subst.fields(oldt.Results()))
1226
1227         newfn.Nname.SetType(newt)
1228         newfn.Body = subst.list(oldfn.Body)
1229
1230         // Remove the nodes for the current closure from subst.inlvars
1231         for _, oldv := range oldfn.Dcl {
1232                 delete(subst.inlvars, oldv)
1233         }
1234         for _, oldv := range oldfn.ClosureVars {
1235                 delete(subst.inlvars, oldv)
1236         }
1237         // Go back to previous closure func
1238         subst.newclofn = prevxfunc
1239
1240         // Actually create the named function for the closure, now that
1241         // the closure is inlined in a specific function.
1242         m.SetTypecheck(0)
1243         if oldfn.ClosureCalled() {
1244                 typecheck.Callee(m)
1245         } else {
1246                 typecheck.Expr(m)
1247         }
1248         return m
1249 }
1250
1251 // node recursively copies a node from the saved pristine body of the
1252 // inlined function, substituting references to input/output
1253 // parameters with ones to the tmpnames, and substituting returns with
1254 // assignments to the output.
1255 func (subst *inlsubst) node(n ir.Node) ir.Node {
1256         if n == nil {
1257                 return nil
1258         }
1259
1260         switch n.Op() {
1261         case ir.ONAME:
1262                 n := n.(*ir.Name)
1263
1264                 // Handle captured variables when inlining closures.
1265                 if n.IsClosureVar() && subst.newclofn == nil {
1266                         o := n.Outer
1267
1268                         // Deal with case where sequence of closures are inlined.
1269                         // TODO(danscales) - write test case to see if we need to
1270                         // go up multiple levels.
1271                         if o.Curfn != ir.CurFunc {
1272                                 o = o.Outer
1273                         }
1274
1275                         // make sure the outer param matches the inlining location
1276                         if o == nil || o.Curfn != ir.CurFunc {
1277                                 base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
1278                         }
1279
1280                         if base.Flag.LowerM > 2 {
1281                                 fmt.Printf("substituting captured name %+v  ->  %+v\n", n, o)
1282                         }
1283                         return o
1284                 }
1285
1286                 if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
1287                         if base.Flag.LowerM > 2 {
1288                                 fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
1289                         }
1290                         return inlvar
1291                 }
1292
1293                 if base.Flag.LowerM > 2 {
1294                         fmt.Printf("not substituting name %+v\n", n)
1295                 }
1296                 return n
1297
1298         case ir.OMETHEXPR:
1299                 n := n.(*ir.SelectorExpr)
1300                 return n
1301
1302         case ir.OLITERAL, ir.ONIL, ir.OTYPE:
1303                 // If n is a named constant or type, we can continue
1304                 // using it in the inline copy. Otherwise, make a copy
1305                 // so we can update the line number.
1306                 if n.Sym() != nil {
1307                         return n
1308                 }
1309
1310         case ir.ORETURN:
1311                 if subst.newclofn != nil {
1312                         // Don't do special substitutions if inside a closure
1313                         break
1314                 }
1315                 // Since we don't handle bodies with closures,
1316                 // this return is guaranteed to belong to the current inlined function.
1317                 n := n.(*ir.ReturnStmt)
1318                 init := subst.list(n.Init())
1319                 if len(subst.retvars) != 0 && len(n.Results) != 0 {
1320                         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
1321
1322                         // Make a shallow copy of retvars.
1323                         // Otherwise OINLCALL.Rlist will be the same list,
1324                         // and later walk and typecheck may clobber it.
1325                         for _, n := range subst.retvars {
1326                                 as.Lhs.Append(n)
1327                         }
1328                         as.Rhs = subst.list(n.Results)
1329
1330                         if subst.delayretvars {
1331                                 for _, n := range as.Lhs {
1332                                         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
1333                                         n.Name().Defn = as
1334                                 }
1335                         }
1336
1337                         init = append(init, typecheck.Stmt(as))
1338                 }
1339                 init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
1340                 typecheck.Stmts(init)
1341                 return ir.NewBlockStmt(base.Pos, init)
1342
1343         case ir.OGOTO:
1344                 n := n.(*ir.BranchStmt)
1345                 m := ir.Copy(n).(*ir.BranchStmt)
1346                 m.SetPos(subst.updatedPos(m.Pos()))
1347                 *m.PtrInit() = nil
1348                 p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
1349                 m.Label = typecheck.Lookup(p)
1350                 return m
1351
1352         case ir.OLABEL:
1353                 if subst.newclofn != nil {
1354                         // Don't do special substitutions if inside a closure
1355                         break
1356                 }
1357                 n := n.(*ir.LabelStmt)
1358                 m := ir.Copy(n).(*ir.LabelStmt)
1359                 m.SetPos(subst.updatedPos(m.Pos()))
1360                 *m.PtrInit() = nil
1361                 p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
1362                 m.Label = typecheck.Lookup(p)
1363                 return m
1364
1365         case ir.OCLOSURE:
1366                 return subst.closure(n.(*ir.ClosureExpr))
1367
1368         }
1369
1370         m := ir.Copy(n)
1371         m.SetPos(subst.updatedPos(m.Pos()))
1372         ir.EditChildren(m, subst.edit)
1373         return m
1374 }
1375
1376 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
1377         pos := base.Ctxt.PosTable.Pos(xpos)
1378         oldbase := pos.Base() // can be nil
1379         newbase := subst.bases[oldbase]
1380         if newbase == nil {
1381                 newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
1382                 subst.bases[oldbase] = newbase
1383         }
1384         pos.SetBase(newbase)
1385         return base.Ctxt.PosTable.XPos(pos)
1386 }
1387
1388 func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
1389         s := make([]*ir.Name, 0, len(ll))
1390         for _, n := range ll {
1391                 if n.Class == ir.PAUTO {
1392                         if !vis.usedLocals.Has(n) {
1393                                 continue
1394                         }
1395                 }
1396                 s = append(s, n)
1397         }
1398         return s
1399 }
1400
1401 // numNonClosures returns the number of functions in list which are not closures.
1402 func numNonClosures(list []*ir.Func) int {
1403         count := 0
1404         for _, fn := range list {
1405                 if fn.OClosure == nil {
1406                         count++
1407                 }
1408         }
1409         return count
1410 }
1411
1412 func doList(list []ir.Node, do func(ir.Node) bool) bool {
1413         for _, x := range list {
1414                 if x != nil {
1415                         if do(x) {
1416                                 return true
1417                         }
1418                 }
1419         }
1420         return false
1421 }