]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/inline/inl.go
cmd/compile: adjust PGO inlining default parameters
[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 CanInline 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         "sort"
33         "strconv"
34         "strings"
35
36         "cmd/compile/internal/base"
37         "cmd/compile/internal/ir"
38         "cmd/compile/internal/logopt"
39         "cmd/compile/internal/pgo"
40         "cmd/compile/internal/typecheck"
41         "cmd/compile/internal/types"
42         "cmd/internal/obj"
43         "cmd/internal/src"
44 )
45
46 // Inlining budget parameters, gathered in one place
47 const (
48         inlineMaxBudget       = 80
49         inlineExtraAppendCost = 0
50         // default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
51         inlineExtraCallCost  = 57              // 57 was benchmarked to provided most benefit with no bad surprises; see https://github.com/golang/go/issues/19348#issuecomment-439370742
52         inlineExtraPanicCost = 1               // do not penalize inlining panics.
53         inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
54
55         inlineBigFunctionNodes   = 5000 // Functions with this many nodes are considered "big".
56         inlineBigFunctionMaxCost = 20   // Max cost of inlinee when inlining into a "big" function.
57 )
58
59 var (
60         // List of all hot callee nodes.
61         // TODO(prattmic): Make this non-global.
62         candHotCalleeMap = make(map[*pgo.IRNode]struct{})
63
64         // List of all hot call sites. CallSiteInfo.Callee is always nil.
65         // TODO(prattmic): Make this non-global.
66         candHotEdgeMap = make(map[pgo.CallSiteInfo]struct{})
67
68         // List of inlined call sites. CallSiteInfo.Callee is always nil.
69         // TODO(prattmic): Make this non-global.
70         inlinedCallSites = make(map[pgo.CallSiteInfo]struct{})
71
72         // Threshold in percentage for hot callsite inlining.
73         inlineHotCallSiteThresholdPercent float64
74
75         // Threshold in CDF percentage for hot callsite inlining,
76         // that is, for a threshold of X the hottest callsites that
77         // make up the top X% of total edge weight will be
78         // considered hot for inlining candidates.
79         inlineCDFHotCallSiteThresholdPercent = float64(99)
80
81         // Budget increased due to hotness.
82         inlineHotMaxBudget int32 = 2000
83 )
84
85 // pgoInlinePrologue records the hot callsites from ir-graph.
86 func pgoInlinePrologue(p *pgo.Profile, decls []ir.Node) {
87         if s, err := strconv.ParseFloat(base.Debug.PGOInlineCDFThreshold, 64); err == nil {
88                 inlineCDFHotCallSiteThresholdPercent = s
89         }
90         var hotCallsites []pgo.NodeMapKey
91         inlineHotCallSiteThresholdPercent, hotCallsites = computeThresholdFromCDF(p)
92         if base.Debug.PGOInline > 0 {
93                 fmt.Printf("hot-callsite-thres-from-CDF=%v\n", inlineHotCallSiteThresholdPercent)
94         }
95
96         if x := base.Debug.PGOInlineBudget; x != 0 {
97                 inlineHotMaxBudget = int32(x)
98         }
99
100         // mark inlineable callees from hot edges
101         for _, n := range hotCallsites {
102                 if fn := p.WeightedCG.IRNodes[n.CalleeName]; fn != nil {
103                         candHotCalleeMap[fn] = struct{}{}
104                 }
105         }
106         // mark hot call sites
107         ir.VisitFuncsBottomUp(decls, func(list []*ir.Func, recursive bool) {
108                 for _, f := range list {
109                         name := ir.PkgFuncName(f)
110                         if n, ok := p.WeightedCG.IRNodes[name]; ok {
111                                 for _, e := range p.WeightedCG.OutEdges[n] {
112                                         if e.Weight != 0 {
113                                                 edgeweightpercent := pgo.WeightInPercentage(e.Weight, p.TotalEdgeWeight)
114                                                 if edgeweightpercent > inlineHotCallSiteThresholdPercent {
115                                                         csi := pgo.CallSiteInfo{LineOffset: e.CallSiteOffset, Caller: n.AST}
116                                                         if _, ok := candHotEdgeMap[csi]; !ok {
117                                                                 candHotEdgeMap[csi] = struct{}{}
118                                                         }
119                                                 }
120                                         }
121                                 }
122                         }
123                 }
124         })
125         if base.Debug.PGOInline >= 2 {
126                 fmt.Printf("hot-cg before inline in dot format:")
127                 p.PrintWeightedCallGraphDOT(inlineHotCallSiteThresholdPercent)
128         }
129 }
130
131 // computeThresholdFromCDF computes an edge weight threshold based on the
132 // CDF of edge weights from the profile. Returns the threshold, and the
133 // list of edges that make up the given percentage of the CDF.
134 func computeThresholdFromCDF(p *pgo.Profile) (float64, []pgo.NodeMapKey) {
135         nodes := make([]pgo.NodeMapKey, len(p.NodeMap))
136         i := 0
137         for n := range p.NodeMap {
138                 nodes[i] = n
139                 i++
140         }
141         sort.Slice(nodes, func(i, j int) bool {
142                 ni, nj := nodes[i], nodes[j]
143                 if wi, wj := p.NodeMap[ni].EWeight, p.NodeMap[nj].EWeight; wi != wj {
144                         return wi > wj // want larger weight first
145                 }
146                 // same weight, order by name/line number
147                 if ni.CallerName != nj.CallerName {
148                         return ni.CallerName < nj.CallerName
149                 }
150                 if ni.CalleeName != nj.CalleeName {
151                         return ni.CalleeName < nj.CalleeName
152                 }
153                 return ni.CallSiteOffset < nj.CallSiteOffset
154         })
155         cum := int64(0)
156         for i, n := range nodes {
157                 w := p.NodeMap[n].EWeight
158                 cum += w
159                 if pgo.WeightInPercentage(cum, p.TotalEdgeWeight) > inlineCDFHotCallSiteThresholdPercent {
160                         return pgo.WeightInPercentage(w, p.TotalEdgeWeight), nodes[:i]
161                 }
162         }
163         return 100, nil
164 }
165
166 // pgoInlineEpilogue updates IRGraph after inlining.
167 func pgoInlineEpilogue(p *pgo.Profile, decls []ir.Node) {
168         if base.Debug.PGOInline >= 2 {
169                 ir.VisitFuncsBottomUp(decls, func(list []*ir.Func, recursive bool) {
170                         for _, f := range list {
171                                 name := ir.PkgFuncName(f)
172                                 if n, ok := p.WeightedCG.IRNodes[name]; ok {
173                                         p.RedirectEdges(n, inlinedCallSites)
174                                 }
175                         }
176                 })
177                 // Print the call-graph after inlining. This is a debugging feature.
178                 fmt.Printf("hot-cg after inline in dot:")
179                 p.PrintWeightedCallGraphDOT(inlineHotCallSiteThresholdPercent)
180         }
181 }
182
183 // InlinePackage finds functions that can be inlined and clones them before walk expands them.
184 func InlinePackage(p *pgo.Profile) {
185         InlineDecls(p, typecheck.Target.Decls, true)
186 }
187
188 // InlineDecls applies inlining to the given batch of declarations.
189 func InlineDecls(p *pgo.Profile, decls []ir.Node, doInline bool) {
190         if p != nil {
191                 pgoInlinePrologue(p, decls)
192         }
193
194         ir.VisitFuncsBottomUp(decls, func(list []*ir.Func, recursive bool) {
195                 numfns := numNonClosures(list)
196                 for _, n := range list {
197                         if !recursive || numfns > 1 {
198                                 // We allow inlining if there is no
199                                 // recursion, or the recursion cycle is
200                                 // across more than one function.
201                                 CanInline(n, p)
202                         } else {
203                                 if base.Flag.LowerM > 1 {
204                                         fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
205                                 }
206                         }
207                         if doInline {
208                                 InlineCalls(n, p)
209                         }
210                 }
211         })
212
213         if p != nil {
214                 pgoInlineEpilogue(p, decls)
215         }
216 }
217
218 // CanInline determines whether fn is inlineable.
219 // If so, CanInline saves copies of fn.Body and fn.Dcl in fn.Inl.
220 // fn and fn.Body will already have been typechecked.
221 func CanInline(fn *ir.Func, profile *pgo.Profile) {
222         if fn.Nname == nil {
223                 base.Fatalf("CanInline no nname %+v", fn)
224         }
225
226         var reason string // reason, if any, that the function was not inlined
227         if base.Flag.LowerM > 1 || logopt.Enabled() {
228                 defer func() {
229                         if reason != "" {
230                                 if base.Flag.LowerM > 1 {
231                                         fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Nname, reason)
232                                 }
233                                 if logopt.Enabled() {
234                                         logopt.LogOpt(fn.Pos(), "cannotInlineFunction", "inline", ir.FuncName(fn), reason)
235                                 }
236                         }
237                 }()
238         }
239
240         // If marked "go:noinline", don't inline
241         if fn.Pragma&ir.Noinline != 0 {
242                 reason = "marked go:noinline"
243                 return
244         }
245
246         // If marked "go:norace" and -race compilation, don't inline.
247         if base.Flag.Race && fn.Pragma&ir.Norace != 0 {
248                 reason = "marked go:norace with -race compilation"
249                 return
250         }
251
252         // If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
253         if base.Debug.Checkptr != 0 && fn.Pragma&ir.NoCheckPtr != 0 {
254                 reason = "marked go:nocheckptr"
255                 return
256         }
257
258         // If marked "go:cgo_unsafe_args", don't inline, since the
259         // function makes assumptions about its argument frame layout.
260         if fn.Pragma&ir.CgoUnsafeArgs != 0 {
261                 reason = "marked go:cgo_unsafe_args"
262                 return
263         }
264
265         // If marked as "go:uintptrkeepalive", don't inline, since the
266         // keep alive information is lost during inlining.
267         //
268         // TODO(prattmic): This is handled on calls during escape analysis,
269         // which is after inlining. Move prior to inlining so the keep-alive is
270         // maintained after inlining.
271         if fn.Pragma&ir.UintptrKeepAlive != 0 {
272                 reason = "marked as having a keep-alive uintptr argument"
273                 return
274         }
275
276         // If marked as "go:uintptrescapes", don't inline, since the
277         // escape information is lost during inlining.
278         if fn.Pragma&ir.UintptrEscapes != 0 {
279                 reason = "marked as having an escaping uintptr argument"
280                 return
281         }
282
283         // The nowritebarrierrec checker currently works at function
284         // granularity, so inlining yeswritebarrierrec functions can
285         // confuse it (#22342). As a workaround, disallow inlining
286         // them for now.
287         if fn.Pragma&ir.Yeswritebarrierrec != 0 {
288                 reason = "marked go:yeswritebarrierrec"
289                 return
290         }
291
292         // If fn has no body (is defined outside of Go), cannot inline it.
293         if len(fn.Body) == 0 {
294                 reason = "no function body"
295                 return
296         }
297
298         if fn.Typecheck() == 0 {
299                 base.Fatalf("CanInline on non-typechecked function %v", fn)
300         }
301
302         n := fn.Nname
303         if n.Func.InlinabilityChecked() {
304                 return
305         }
306         defer n.Func.SetInlinabilityChecked(true)
307
308         cc := int32(inlineExtraCallCost)
309         if base.Flag.LowerL == 4 {
310                 cc = 1 // this appears to yield better performance than 0.
311         }
312
313         // Update the budget for profile-guided inlining.
314         budget := int32(inlineMaxBudget)
315         if profile != nil {
316                 if n, ok := profile.WeightedCG.IRNodes[ir.PkgFuncName(fn)]; ok {
317                         if _, ok := candHotCalleeMap[n]; ok {
318                                 budget = int32(inlineHotMaxBudget)
319                                 if base.Debug.PGOInline > 0 {
320                                         fmt.Printf("hot-node enabled increased budget=%v for func=%v\n", budget, ir.PkgFuncName(fn))
321                                 }
322                         }
323                 }
324         }
325
326         // At this point in the game the function we're looking at may
327         // have "stale" autos, vars that still appear in the Dcl list, but
328         // which no longer have any uses in the function body (due to
329         // elimination by deadcode). We'd like to exclude these dead vars
330         // when creating the "Inline.Dcl" field below; to accomplish this,
331         // the hairyVisitor below builds up a map of used/referenced
332         // locals, and we use this map to produce a pruned Inline.Dcl
333         // list. See issue 25249 for more context.
334
335         visitor := hairyVisitor{
336                 curFunc:       fn,
337                 budget:        budget,
338                 maxBudget:     budget,
339                 extraCallCost: cc,
340                 profile:       profile,
341         }
342         if visitor.tooHairy(fn) {
343                 reason = visitor.reason
344                 return
345         }
346
347         n.Func.Inl = &ir.Inline{
348                 Cost: budget - visitor.budget,
349                 Dcl:  pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor),
350                 Body: inlcopylist(fn.Body),
351
352                 CanDelayResults: canDelayResults(fn),
353         }
354
355         if base.Flag.LowerM > 1 {
356                 fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, budget-visitor.budget, fn.Type(), ir.Nodes(n.Func.Inl.Body))
357         } else if base.Flag.LowerM != 0 {
358                 fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
359         }
360         if logopt.Enabled() {
361                 logopt.LogOpt(fn.Pos(), "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", budget-visitor.budget))
362         }
363 }
364
365 // canDelayResults reports whether inlined calls to fn can delay
366 // declaring the result parameter until the "return" statement.
367 func canDelayResults(fn *ir.Func) bool {
368         // We can delay declaring+initializing result parameters if:
369         // (1) there's exactly one "return" statement in the inlined function;
370         // (2) it's not an empty return statement (#44355); and
371         // (3) the result parameters aren't named.
372
373         nreturns := 0
374         ir.VisitList(fn.Body, func(n ir.Node) {
375                 if n, ok := n.(*ir.ReturnStmt); ok {
376                         nreturns++
377                         if len(n.Results) == 0 {
378                                 nreturns++ // empty return statement (case 2)
379                         }
380                 }
381         })
382
383         if nreturns != 1 {
384                 return false // not exactly one return statement (case 1)
385         }
386
387         // temporaries for return values.
388         for _, param := range fn.Type().Results().FieldSlice() {
389                 if sym := types.OrigSym(param.Sym); sym != nil && !sym.IsBlank() {
390                         return false // found a named result parameter (case 3)
391                 }
392         }
393
394         return true
395 }
396
397 // hairyVisitor visits a function body to determine its inlining
398 // hairiness and whether or not it can be inlined.
399 type hairyVisitor struct {
400         // This is needed to access the current caller in the doNode function.
401         curFunc       *ir.Func
402         budget        int32
403         maxBudget     int32
404         reason        string
405         extraCallCost int32
406         usedLocals    ir.NameSet
407         do            func(ir.Node) bool
408         profile       *pgo.Profile
409 }
410
411 func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
412         v.do = v.doNode // cache closure
413         if ir.DoChildren(fn, v.do) {
414                 return true
415         }
416         if v.budget < 0 {
417                 v.reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", v.maxBudget-v.budget, v.maxBudget)
418                 return true
419         }
420         return false
421 }
422
423 func (v *hairyVisitor) doNode(n ir.Node) bool {
424         if n == nil {
425                 return false
426         }
427         switch n.Op() {
428         // Call is okay if inlinable and we have the budget for the body.
429         case ir.OCALLFUNC:
430                 n := n.(*ir.CallExpr)
431                 // Functions that call runtime.getcaller{pc,sp} can not be inlined
432                 // because getcaller{pc,sp} expect a pointer to the caller's first argument.
433                 //
434                 // runtime.throw is a "cheap call" like panic in normal code.
435                 if n.X.Op() == ir.ONAME {
436                         name := n.X.(*ir.Name)
437                         if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
438                                 fn := name.Sym().Name
439                                 if fn == "getcallerpc" || fn == "getcallersp" {
440                                         v.reason = "call to " + fn
441                                         return true
442                                 }
443                                 if fn == "throw" {
444                                         v.budget -= inlineExtraThrowCost
445                                         break
446                                 }
447                         }
448                         // Special case for coverage counter updates; although
449                         // these correspond to real operations, we treat them as
450                         // zero cost for the moment. This is due to the existence
451                         // of tests that are sensitive to inlining-- if the
452                         // insertion of coverage instrumentation happens to tip a
453                         // given function over the threshold and move it from
454                         // "inlinable" to "not-inlinable", this can cause changes
455                         // in allocation behavior, which can then result in test
456                         // failures (a good example is the TestAllocations in
457                         // crypto/ed25519).
458                         if isAtomicCoverageCounterUpdate(n) {
459                                 return false
460                         }
461                 }
462                 if n.X.Op() == ir.OMETHEXPR {
463                         if meth := ir.MethodExprName(n.X); meth != nil {
464                                 if fn := meth.Func; fn != nil {
465                                         s := fn.Sym()
466                                         var cheap bool
467                                         if types.IsRuntimePkg(s.Pkg) && s.Name == "heapBits.nextArena" {
468                                                 // Special case: explicitly allow mid-stack inlining of
469                                                 // runtime.heapBits.next even though it calls slow-path
470                                                 // runtime.heapBits.nextArena.
471                                                 cheap = true
472                                         }
473                                         // Special case: on architectures that can do unaligned loads,
474                                         // explicitly mark encoding/binary methods as cheap,
475                                         // because in practice they are, even though our inlining
476                                         // budgeting system does not see that. See issue 42958.
477                                         if base.Ctxt.Arch.CanMergeLoads && s.Pkg.Path == "encoding/binary" {
478                                                 switch s.Name {
479                                                 case "littleEndian.Uint64", "littleEndian.Uint32", "littleEndian.Uint16",
480                                                         "bigEndian.Uint64", "bigEndian.Uint32", "bigEndian.Uint16",
481                                                         "littleEndian.PutUint64", "littleEndian.PutUint32", "littleEndian.PutUint16",
482                                                         "bigEndian.PutUint64", "bigEndian.PutUint32", "bigEndian.PutUint16",
483                                                         "littleEndian.AppendUint64", "littleEndian.AppendUint32", "littleEndian.AppendUint16",
484                                                         "bigEndian.AppendUint64", "bigEndian.AppendUint32", "bigEndian.AppendUint16":
485                                                         cheap = true
486                                                 }
487                                         }
488                                         if cheap {
489                                                 break // treat like any other node, that is, cost of 1
490                                         }
491                                 }
492                         }
493                 }
494
495                 // Determine if the callee edge is for an inlinable hot callee or not.
496                 if v.profile != nil && v.curFunc != nil {
497                         if fn := inlCallee(n.X, v.profile); fn != nil && typecheck.HaveInlineBody(fn) {
498                                 lineOffset := pgo.NodeLineOffset(n, fn)
499                                 csi := pgo.CallSiteInfo{LineOffset: lineOffset, Caller: v.curFunc}
500                                 if _, o := candHotEdgeMap[csi]; o {
501                                         if base.Debug.PGOInline > 0 {
502                                                 fmt.Printf("hot-callsite identified at line=%v for func=%v\n", ir.Line(n), ir.PkgFuncName(v.curFunc))
503                                         }
504                                 }
505                         }
506                 }
507
508                 if ir.IsIntrinsicCall(n) {
509                         // Treat like any other node.
510                         break
511                 }
512
513                 if fn := inlCallee(n.X, v.profile); fn != nil && typecheck.HaveInlineBody(fn) {
514                         v.budget -= fn.Inl.Cost
515                         break
516                 }
517
518                 // Call cost for non-leaf inlining.
519                 v.budget -= v.extraCallCost
520
521         case ir.OCALLMETH:
522                 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
523
524         // Things that are too hairy, irrespective of the budget
525         case ir.OCALL, ir.OCALLINTER:
526                 // Call cost for non-leaf inlining.
527                 v.budget -= v.extraCallCost
528
529         case ir.OPANIC:
530                 n := n.(*ir.UnaryExpr)
531                 if n.X.Op() == ir.OCONVIFACE && n.X.(*ir.ConvExpr).Implicit() {
532                         // Hack to keep reflect.flag.mustBe inlinable for TestIntendedInlining.
533                         // Before CL 284412, these conversions were introduced later in the
534                         // compiler, so they didn't count against inlining budget.
535                         v.budget++
536                 }
537                 v.budget -= inlineExtraPanicCost
538
539         case ir.ORECOVER:
540                 // recover matches the argument frame pointer to find
541                 // the right panic value, so it needs an argument frame.
542                 v.reason = "call to recover"
543                 return true
544
545         case ir.OCLOSURE:
546                 if base.Debug.InlFuncsWithClosures == 0 {
547                         v.reason = "not inlining functions with closures"
548                         return true
549                 }
550
551                 // TODO(danscales): Maybe make budget proportional to number of closure
552                 // variables, e.g.:
553                 //v.budget -= int32(len(n.(*ir.ClosureExpr).Func.ClosureVars) * 3)
554                 v.budget -= 15
555                 // Scan body of closure (which DoChildren doesn't automatically
556                 // do) to check for disallowed ops in the body and include the
557                 // body in the budget.
558                 if doList(n.(*ir.ClosureExpr).Func.Body, v.do) {
559                         return true
560                 }
561
562         case ir.OGO,
563                 ir.ODEFER,
564                 ir.ODCLTYPE, // can't print yet
565                 ir.OTAILCALL:
566                 v.reason = "unhandled op " + n.Op().String()
567                 return true
568
569         case ir.OAPPEND:
570                 v.budget -= inlineExtraAppendCost
571
572         case ir.OADDR:
573                 n := n.(*ir.AddrExpr)
574                 // Make "&s.f" cost 0 when f's offset is zero.
575                 if dot, ok := n.X.(*ir.SelectorExpr); ok && (dot.Op() == ir.ODOT || dot.Op() == ir.ODOTPTR) {
576                         if _, ok := dot.X.(*ir.Name); ok && dot.Selection.Offset == 0 {
577                                 v.budget += 2 // undo ir.OADDR+ir.ODOT/ir.ODOTPTR
578                         }
579                 }
580
581         case ir.ODEREF:
582                 // *(*X)(unsafe.Pointer(&x)) is low-cost
583                 n := n.(*ir.StarExpr)
584
585                 ptr := n.X
586                 for ptr.Op() == ir.OCONVNOP {
587                         ptr = ptr.(*ir.ConvExpr).X
588                 }
589                 if ptr.Op() == ir.OADDR {
590                         v.budget += 1 // undo half of default cost of ir.ODEREF+ir.OADDR
591                 }
592
593         case ir.OCONVNOP:
594                 // This doesn't produce code, but the children might.
595                 v.budget++ // undo default cost
596
597         case ir.ODCLCONST, ir.OFALL:
598                 // These nodes don't produce code; omit from inlining budget.
599                 return false
600
601         case ir.OIF:
602                 n := n.(*ir.IfStmt)
603                 if ir.IsConst(n.Cond, constant.Bool) {
604                         // This if and the condition cost nothing.
605                         if doList(n.Init(), v.do) {
606                                 return true
607                         }
608                         if ir.BoolVal(n.Cond) {
609                                 return doList(n.Body, v.do)
610                         } else {
611                                 return doList(n.Else, v.do)
612                         }
613                 }
614
615         case ir.ONAME:
616                 n := n.(*ir.Name)
617                 if n.Class == ir.PAUTO {
618                         v.usedLocals.Add(n)
619                 }
620
621         case ir.OBLOCK:
622                 // The only OBLOCK we should see at this point is an empty one.
623                 // In any event, let the visitList(n.List()) below take care of the statements,
624                 // and don't charge for the OBLOCK itself. The ++ undoes the -- below.
625                 v.budget++
626
627         case ir.OMETHVALUE, ir.OSLICELIT:
628                 v.budget-- // Hack for toolstash -cmp.
629
630         case ir.OMETHEXPR:
631                 v.budget++ // Hack for toolstash -cmp.
632
633         case ir.OAS2:
634                 n := n.(*ir.AssignListStmt)
635
636                 // Unified IR unconditionally rewrites:
637                 //
638                 //      a, b = f()
639                 //
640                 // into:
641                 //
642                 //      DCL tmp1
643                 //      DCL tmp2
644                 //      tmp1, tmp2 = f()
645                 //      a, b = tmp1, tmp2
646                 //
647                 // so that it can insert implicit conversions as necessary. To
648                 // minimize impact to the existing inlining heuristics (in
649                 // particular, to avoid breaking the existing inlinability regress
650                 // tests), we need to compensate for this here.
651                 if base.Debug.Unified != 0 {
652                         if init := n.Rhs[0].Init(); len(init) == 1 {
653                                 if _, ok := init[0].(*ir.AssignListStmt); ok {
654                                         // 4 for each value, because each temporary variable now
655                                         // appears 3 times (DCL, LHS, RHS), plus an extra DCL node.
656                                         //
657                                         // 1 for the extra "tmp1, tmp2 = f()" assignment statement.
658                                         v.budget += 4*int32(len(n.Lhs)) + 1
659                                 }
660                         }
661                 }
662
663         case ir.OAS:
664                 // Special case for coverage counter updates and coverage
665                 // function registrations. Although these correspond to real
666                 // operations, we treat them as zero cost for the moment. This
667                 // is primarily due to the existence of tests that are
668                 // sensitive to inlining-- if the insertion of coverage
669                 // instrumentation happens to tip a given function over the
670                 // threshold and move it from "inlinable" to "not-inlinable",
671                 // this can cause changes in allocation behavior, which can
672                 // then result in test failures (a good example is the
673                 // TestAllocations in crypto/ed25519).
674                 n := n.(*ir.AssignStmt)
675                 if n.X.Op() == ir.OINDEX && isIndexingCoverageCounter(n.X) {
676                         return false
677                 }
678         }
679
680         v.budget--
681
682         // When debugging, don't stop early, to get full cost of inlining this function
683         if v.budget < 0 && base.Flag.LowerM < 2 && !logopt.Enabled() {
684                 v.reason = "too expensive"
685                 return true
686         }
687
688         return ir.DoChildren(n, v.do)
689 }
690
691 func isBigFunc(fn *ir.Func) bool {
692         budget := inlineBigFunctionNodes
693         return ir.Any(fn, func(n ir.Node) bool {
694                 budget--
695                 return budget <= 0
696         })
697 }
698
699 // inlcopylist (together with inlcopy) recursively copies a list of nodes, except
700 // that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
701 // the body and dcls of an inlineable function.
702 func inlcopylist(ll []ir.Node) []ir.Node {
703         s := make([]ir.Node, len(ll))
704         for i, n := range ll {
705                 s[i] = inlcopy(n)
706         }
707         return s
708 }
709
710 // inlcopy is like DeepCopy(), but does extra work to copy closures.
711 func inlcopy(n ir.Node) ir.Node {
712         var edit func(ir.Node) ir.Node
713         edit = func(x ir.Node) ir.Node {
714                 switch x.Op() {
715                 case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
716                         return x
717                 }
718                 m := ir.Copy(x)
719                 ir.EditChildren(m, edit)
720                 if x.Op() == ir.OCLOSURE {
721                         x := x.(*ir.ClosureExpr)
722                         // Need to save/duplicate x.Func.Nname,
723                         // x.Func.Nname.Ntype, x.Func.Dcl, x.Func.ClosureVars, and
724                         // x.Func.Body for iexport and local inlining.
725                         oldfn := x.Func
726                         newfn := ir.NewFunc(oldfn.Pos())
727                         m.(*ir.ClosureExpr).Func = newfn
728                         newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym())
729                         // XXX OK to share fn.Type() ??
730                         newfn.Nname.SetType(oldfn.Nname.Type())
731                         newfn.Body = inlcopylist(oldfn.Body)
732                         // Make shallow copy of the Dcl and ClosureVar slices
733                         newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...)
734                         newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...)
735                 }
736                 return m
737         }
738         return edit(n)
739 }
740
741 // InlineCalls/inlnode walks fn's statements and expressions and substitutes any
742 // calls made to inlineable functions. This is the external entry point.
743 func InlineCalls(fn *ir.Func, profile *pgo.Profile) {
744         savefn := ir.CurFunc
745         ir.CurFunc = fn
746         maxCost := int32(inlineMaxBudget)
747         if isBigFunc(fn) {
748                 maxCost = inlineBigFunctionMaxCost
749         }
750         var inlCalls []*ir.InlinedCallExpr
751         var edit func(ir.Node) ir.Node
752         edit = func(n ir.Node) ir.Node {
753                 return inlnode(n, maxCost, &inlCalls, edit, profile)
754         }
755         ir.EditChildren(fn, edit)
756
757         // If we inlined any calls, we want to recursively visit their
758         // bodies for further inlining. However, we need to wait until
759         // *after* the original function body has been expanded, or else
760         // inlCallee can have false positives (e.g., #54632).
761         for len(inlCalls) > 0 {
762                 call := inlCalls[0]
763                 inlCalls = inlCalls[1:]
764                 ir.EditChildren(call, edit)
765         }
766
767         ir.CurFunc = savefn
768 }
769
770 // inlnode recurses over the tree to find inlineable calls, which will
771 // be turned into OINLCALLs by mkinlcall. When the recursion comes
772 // back up will examine left, right, list, rlist, ninit, ntest, nincr,
773 // nbody and nelse and use one of the 4 inlconv/glue functions above
774 // to turn the OINLCALL into an expression, a statement, or patch it
775 // in to this nodes list or rlist as appropriate.
776 // NOTE it makes no sense to pass the glue functions down the
777 // recursion to the level where the OINLCALL gets created because they
778 // have to edit /this/ n, so you'd have to push that one down as well,
779 // but then you may as well do it here.  so this is cleaner and
780 // shorter and less complicated.
781 // The result of inlnode MUST be assigned back to n, e.g.
782 //
783 //      n.Left = inlnode(n.Left)
784 func inlnode(n ir.Node, maxCost int32, inlCalls *[]*ir.InlinedCallExpr, edit func(ir.Node) ir.Node, profile *pgo.Profile) ir.Node {
785         if n == nil {
786                 return n
787         }
788
789         switch n.Op() {
790         case ir.ODEFER, ir.OGO:
791                 n := n.(*ir.GoDeferStmt)
792                 switch call := n.Call; call.Op() {
793                 case ir.OCALLMETH:
794                         base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
795                 case ir.OCALLFUNC:
796                         call := call.(*ir.CallExpr)
797                         call.NoInline = true
798                 }
799         case ir.OTAILCALL:
800                 n := n.(*ir.TailCallStmt)
801                 n.Call.NoInline = true // Not inline a tail call for now. Maybe we could inline it just like RETURN fn(arg)?
802
803         // TODO do them here (or earlier),
804         // so escape analysis can avoid more heapmoves.
805         case ir.OCLOSURE:
806                 return n
807         case ir.OCALLMETH:
808                 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
809         case ir.OCALLFUNC:
810                 n := n.(*ir.CallExpr)
811                 if n.X.Op() == ir.OMETHEXPR {
812                         // Prevent inlining some reflect.Value methods when using checkptr,
813                         // even when package reflect was compiled without it (#35073).
814                         if meth := ir.MethodExprName(n.X); meth != nil {
815                                 s := meth.Sym()
816                                 if base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
817                                         return n
818                                 }
819                         }
820                 }
821         }
822
823         lno := ir.SetPos(n)
824
825         ir.EditChildren(n, edit)
826
827         // with all the branches out of the way, it is now time to
828         // transmogrify this node itself unless inhibited by the
829         // switch at the top of this function.
830         switch n.Op() {
831         case ir.OCALLMETH:
832                 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
833
834         case ir.OCALLFUNC:
835                 call := n.(*ir.CallExpr)
836                 if call.NoInline {
837                         break
838                 }
839                 if base.Flag.LowerM > 3 {
840                         fmt.Printf("%v:call to func %+v\n", ir.Line(n), call.X)
841                 }
842                 if ir.IsIntrinsicCall(call) {
843                         break
844                 }
845                 if fn := inlCallee(call.X, profile); fn != nil && typecheck.HaveInlineBody(fn) {
846                         n = mkinlcall(call, fn, maxCost, inlCalls, edit)
847                 }
848         }
849
850         base.Pos = lno
851
852         return n
853 }
854
855 // inlCallee takes a function-typed expression and returns the underlying function ONAME
856 // that it refers to if statically known. Otherwise, it returns nil.
857 func inlCallee(fn ir.Node, profile *pgo.Profile) *ir.Func {
858         fn = ir.StaticValue(fn)
859         switch fn.Op() {
860         case ir.OMETHEXPR:
861                 fn := fn.(*ir.SelectorExpr)
862                 n := ir.MethodExprName(fn)
863                 // Check that receiver type matches fn.X.
864                 // TODO(mdempsky): Handle implicit dereference
865                 // of pointer receiver argument?
866                 if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
867                         return nil
868                 }
869                 return n.Func
870         case ir.ONAME:
871                 fn := fn.(*ir.Name)
872                 if fn.Class == ir.PFUNC {
873                         return fn.Func
874                 }
875         case ir.OCLOSURE:
876                 fn := fn.(*ir.ClosureExpr)
877                 c := fn.Func
878                 CanInline(c, profile)
879                 return c
880         }
881         return nil
882 }
883
884 func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
885         if t.Nname == nil {
886                 return ir.BlankNode
887         }
888         n := t.Nname.(*ir.Name)
889         if ir.IsBlank(n) {
890                 return ir.BlankNode
891         }
892         inlvar := inlvars[n]
893         if inlvar == nil {
894                 base.Fatalf("missing inlvar for %v", n)
895         }
896         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
897         inlvar.Name().Defn = as
898         return inlvar
899 }
900
901 var inlgen int
902
903 // SSADumpInline gives the SSA back end a chance to dump the function
904 // when producing output for debugging the compiler itself.
905 var SSADumpInline = func(*ir.Func) {}
906
907 // InlineCall allows the inliner implementation to be overridden.
908 // If it returns nil, the function will not be inlined.
909 var InlineCall = oldInlineCall
910
911 // If n is a OCALLFUNC node, and fn is an ONAME node for a
912 // function with an inlinable body, return an OINLCALL node that can replace n.
913 // The returned node's Ninit has the parameter assignments, the Nbody is the
914 // inlined function body, and (List, Rlist) contain the (input, output)
915 // parameters.
916 // The result of mkinlcall MUST be assigned back to n, e.g.
917 //
918 //      n.Left = mkinlcall(n.Left, fn, isddd)
919 func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlCalls *[]*ir.InlinedCallExpr, edit func(ir.Node) ir.Node) ir.Node {
920         if fn.Inl == nil {
921                 if logopt.Enabled() {
922                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
923                                 fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
924                 }
925                 return n
926         }
927         if fn.Inl.Cost > maxCost {
928                 // If the callsite is hot and it is under the inlineHotMaxBudget budget, then try to inline it, or else bail.
929                 lineOffset := pgo.NodeLineOffset(n, ir.CurFunc)
930                 csi := pgo.CallSiteInfo{LineOffset: lineOffset, Caller: ir.CurFunc}
931                 if _, ok := candHotEdgeMap[csi]; ok {
932                         if fn.Inl.Cost > inlineHotMaxBudget {
933                                 if logopt.Enabled() {
934                                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
935                                                 fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), inlineHotMaxBudget))
936                                 }
937                                 return n
938                         }
939                         if base.Debug.PGOInline > 0 {
940                                 fmt.Printf("hot-budget check allows inlining for call %s at %v\n", ir.PkgFuncName(fn), ir.Line(n))
941                         }
942                 } else {
943                         // The inlined function body is too big. Typically we use this check to restrict
944                         // inlining into very big functions.  See issue 26546 and 17566.
945                         if logopt.Enabled() {
946                                 logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
947                                         fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), maxCost))
948                         }
949                         return n
950                 }
951         }
952
953         if fn == ir.CurFunc {
954                 // Can't recursively inline a function into itself.
955                 if logopt.Enabled() {
956                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(ir.CurFunc)))
957                 }
958                 return n
959         }
960
961         // The non-unified frontend has issues with inlining and shape parameters.
962         if base.Debug.Unified == 0 {
963                 // Don't inline a function fn that has no shape parameters, but is passed at
964                 // least one shape arg. This means we must be inlining a non-generic function
965                 // fn that was passed into a generic function, and can be called with a shape
966                 // arg because it matches an appropriate type parameters. But fn may include
967                 // an interface conversion (that may be applied to a shape arg) that was not
968                 // apparent when we first created the instantiation of the generic function.
969                 // We can't handle this if we actually do the inlining, since we want to know
970                 // all interface conversions immediately after stenciling. So, we avoid
971                 // inlining in this case, see issue #49309. (1)
972                 //
973                 // See discussion on go.dev/cl/406475 for more background.
974                 if !fn.Type().Params().HasShape() {
975                         for _, arg := range n.Args {
976                                 if arg.Type().HasShape() {
977                                         if logopt.Enabled() {
978                                                 logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
979                                                         fmt.Sprintf("inlining function %v has no-shape params with shape args", ir.FuncName(fn)))
980                                         }
981                                         return n
982                                 }
983                         }
984                 } else {
985                         // Don't inline a function fn that has shape parameters, but is passed no shape arg.
986                         // See comments (1) above, and issue #51909.
987                         inlineable := len(n.Args) == 0 // Function has shape in type, with no arguments can always be inlined.
988                         for _, arg := range n.Args {
989                                 if arg.Type().HasShape() {
990                                         inlineable = true
991                                         break
992                                 }
993                         }
994                         if !inlineable {
995                                 if logopt.Enabled() {
996                                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
997                                                 fmt.Sprintf("inlining function %v has shape params with no-shape args", ir.FuncName(fn)))
998                                 }
999                                 return n
1000                         }
1001                 }
1002         }
1003
1004         if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
1005                 // Runtime package must not be instrumented.
1006                 // Instrument skips runtime package. However, some runtime code can be
1007                 // inlined into other packages and instrumented there. To avoid this,
1008                 // we disable inlining of runtime functions when instrumenting.
1009                 // The example that we observed is inlining of LockOSThread,
1010                 // which lead to false race reports on m contents.
1011                 return n
1012         }
1013
1014         parent := base.Ctxt.PosTable.Pos(n.Pos()).Base().InliningIndex()
1015         sym := fn.Linksym()
1016
1017         // Check if we've already inlined this function at this particular
1018         // call site, in order to stop inlining when we reach the beginning
1019         // of a recursion cycle again. We don't inline immediately recursive
1020         // functions, but allow inlining if there is a recursion cycle of
1021         // many functions. Most likely, the inlining will stop before we
1022         // even hit the beginning of the cycle again, but this catches the
1023         // unusual case.
1024         for inlIndex := parent; inlIndex >= 0; inlIndex = base.Ctxt.InlTree.Parent(inlIndex) {
1025                 if base.Ctxt.InlTree.InlinedFunction(inlIndex) == sym {
1026                         if base.Flag.LowerM > 1 {
1027                                 fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", ir.Line(n), fn, ir.FuncName(ir.CurFunc))
1028                         }
1029                         return n
1030                 }
1031         }
1032
1033         typecheck.FixVariadicCall(n)
1034
1035         inlIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
1036
1037         closureInitLSym := func(n *ir.CallExpr, fn *ir.Func) {
1038                 // The linker needs FuncInfo metadata for all inlined
1039                 // functions. This is typically handled by gc.enqueueFunc
1040                 // calling ir.InitLSym for all function declarations in
1041                 // typecheck.Target.Decls (ir.UseClosure adds all closures to
1042                 // Decls).
1043                 //
1044                 // However, non-trivial closures in Decls are ignored, and are
1045                 // insteaded enqueued when walk of the calling function
1046                 // discovers them.
1047                 //
1048                 // This presents a problem for direct calls to closures.
1049                 // Inlining will replace the entire closure definition with its
1050                 // body, which hides the closure from walk and thus suppresses
1051                 // symbol creation.
1052                 //
1053                 // Explicitly create a symbol early in this edge case to ensure
1054                 // we keep this metadata.
1055                 //
1056                 // TODO: Refactor to keep a reference so this can all be done
1057                 // by enqueueFunc.
1058
1059                 if n.Op() != ir.OCALLFUNC {
1060                         // Not a standard call.
1061                         return
1062                 }
1063                 if n.X.Op() != ir.OCLOSURE {
1064                         // Not a direct closure call.
1065                         return
1066                 }
1067
1068                 clo := n.X.(*ir.ClosureExpr)
1069                 if ir.IsTrivialClosure(clo) {
1070                         // enqueueFunc will handle trivial closures anyways.
1071                         return
1072                 }
1073
1074                 ir.InitLSym(fn, true)
1075         }
1076
1077         closureInitLSym(n, fn)
1078
1079         if base.Flag.GenDwarfInl > 0 {
1080                 if !sym.WasInlined() {
1081                         base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn)
1082                         sym.Set(obj.AttrWasInlined, true)
1083                 }
1084         }
1085
1086         if base.Flag.LowerM != 0 {
1087                 fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
1088         }
1089         if base.Flag.LowerM > 2 {
1090                 fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
1091         }
1092
1093         if base.Debug.PGOInline > 0 {
1094                 csi := pgo.CallSiteInfo{LineOffset: pgo.NodeLineOffset(n, fn), Caller: ir.CurFunc}
1095                 if _, ok := inlinedCallSites[csi]; !ok {
1096                         inlinedCallSites[csi] = struct{}{}
1097                 }
1098         }
1099
1100         res := InlineCall(n, fn, inlIndex)
1101
1102         if res == nil {
1103                 base.FatalfAt(n.Pos(), "inlining call to %v failed", fn)
1104         }
1105
1106         if base.Flag.LowerM > 2 {
1107                 fmt.Printf("%v: After inlining %+v\n\n", ir.Line(res), res)
1108         }
1109
1110         *inlCalls = append(*inlCalls, res)
1111
1112         return res
1113 }
1114
1115 // CalleeEffects appends any side effects from evaluating callee to init.
1116 func CalleeEffects(init *ir.Nodes, callee ir.Node) {
1117         for {
1118                 init.Append(ir.TakeInit(callee)...)
1119
1120                 switch callee.Op() {
1121                 case ir.ONAME, ir.OCLOSURE, ir.OMETHEXPR:
1122                         return // done
1123
1124                 case ir.OCONVNOP:
1125                         conv := callee.(*ir.ConvExpr)
1126                         callee = conv.X
1127
1128                 case ir.OINLCALL:
1129                         ic := callee.(*ir.InlinedCallExpr)
1130                         init.Append(ic.Body.Take()...)
1131                         callee = ic.SingleResult()
1132
1133                 default:
1134                         base.FatalfAt(callee.Pos(), "unexpected callee expression: %v", callee)
1135                 }
1136         }
1137 }
1138
1139 // oldInlineCall creates an InlinedCallExpr to replace the given call
1140 // expression. fn is the callee function to be inlined. inlIndex is
1141 // the inlining tree position index, for use with src.NewInliningBase
1142 // when rewriting positions.
1143 func oldInlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr {
1144         if base.Debug.TypecheckInl == 0 {
1145                 typecheck.ImportedBody(fn)
1146         }
1147
1148         SSADumpInline(fn)
1149
1150         ninit := call.Init()
1151
1152         // For normal function calls, the function callee expression
1153         // may contain side effects. Make sure to preserve these,
1154         // if necessary (#42703).
1155         if call.Op() == ir.OCALLFUNC {
1156                 CalleeEffects(&ninit, call.X)
1157         }
1158
1159         // Make temp names to use instead of the originals.
1160         inlvars := make(map[*ir.Name]*ir.Name)
1161
1162         // record formals/locals for later post-processing
1163         var inlfvars []*ir.Name
1164
1165         for _, ln := range fn.Inl.Dcl {
1166                 if ln.Op() != ir.ONAME {
1167                         continue
1168                 }
1169                 if ln.Class == ir.PPARAMOUT { // return values handled below.
1170                         continue
1171                 }
1172                 inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
1173                 inlvars[ln] = inlf
1174                 if base.Flag.GenDwarfInl > 0 {
1175                         if ln.Class == ir.PPARAM {
1176                                 inlf.Name().SetInlFormal(true)
1177                         } else {
1178                                 inlf.Name().SetInlLocal(true)
1179                         }
1180                         inlf.SetPos(ln.Pos())
1181                         inlfvars = append(inlfvars, inlf)
1182                 }
1183         }
1184
1185         // We can delay declaring+initializing result parameters if:
1186         // temporaries for return values.
1187         var retvars []ir.Node
1188         for i, t := range fn.Type().Results().Fields().Slice() {
1189                 var m *ir.Name
1190                 if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
1191                         n := nn.(*ir.Name)
1192                         m = inlvar(n)
1193                         m = typecheck.Expr(m).(*ir.Name)
1194                         inlvars[n] = m
1195                 } else {
1196                         // anonymous return values, synthesize names for use in assignment that replaces return
1197                         m = retvar(t, i)
1198                 }
1199
1200                 if base.Flag.GenDwarfInl > 0 {
1201                         // Don't update the src.Pos on a return variable if it
1202                         // was manufactured by the inliner (e.g. "~R2"); such vars
1203                         // were not part of the original callee.
1204                         if !strings.HasPrefix(m.Sym().Name, "~R") {
1205                                 m.Name().SetInlFormal(true)
1206                                 m.SetPos(t.Pos)
1207                                 inlfvars = append(inlfvars, m)
1208                         }
1209                 }
1210
1211                 retvars = append(retvars, m)
1212         }
1213
1214         // Assign arguments to the parameters' temp names.
1215         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
1216         as.Def = true
1217         if call.Op() == ir.OCALLMETH {
1218                 base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
1219         }
1220         as.Rhs.Append(call.Args...)
1221
1222         if recv := fn.Type().Recv(); recv != nil {
1223                 as.Lhs.Append(inlParam(recv, as, inlvars))
1224         }
1225         for _, param := range fn.Type().Params().Fields().Slice() {
1226                 as.Lhs.Append(inlParam(param, as, inlvars))
1227         }
1228
1229         if len(as.Rhs) != 0 {
1230                 ninit.Append(typecheck.Stmt(as))
1231         }
1232
1233         if !fn.Inl.CanDelayResults {
1234                 // Zero the return parameters.
1235                 for _, n := range retvars {
1236                         ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
1237                         ras := ir.NewAssignStmt(base.Pos, n, nil)
1238                         ninit.Append(typecheck.Stmt(ras))
1239                 }
1240         }
1241
1242         retlabel := typecheck.AutoLabel(".i")
1243
1244         inlgen++
1245
1246         // Add an inline mark just before the inlined body.
1247         // This mark is inline in the code so that it's a reasonable spot
1248         // to put a breakpoint. Not sure if that's really necessary or not
1249         // (in which case it could go at the end of the function instead).
1250         // Note issue 28603.
1251         ninit.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(inlIndex)))
1252
1253         subst := inlsubst{
1254                 retlabel:    retlabel,
1255                 retvars:     retvars,
1256                 inlvars:     inlvars,
1257                 defnMarker:  ir.NilExpr{},
1258                 bases:       make(map[*src.PosBase]*src.PosBase),
1259                 newInlIndex: inlIndex,
1260                 fn:          fn,
1261         }
1262         subst.edit = subst.node
1263
1264         body := subst.list(ir.Nodes(fn.Inl.Body))
1265
1266         lab := ir.NewLabelStmt(base.Pos, retlabel)
1267         body = append(body, lab)
1268
1269         if base.Flag.GenDwarfInl > 0 {
1270                 for _, v := range inlfvars {
1271                         v.SetPos(subst.updatedPos(v.Pos()))
1272                 }
1273         }
1274
1275         //dumplist("ninit post", ninit);
1276
1277         res := ir.NewInlinedCallExpr(base.Pos, body, retvars)
1278         res.SetInit(ninit)
1279         res.SetType(call.Type())
1280         res.SetTypecheck(1)
1281         return res
1282 }
1283
1284 // Every time we expand a function we generate a new set of tmpnames,
1285 // PAUTO's in the calling functions, and link them off of the
1286 // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
1287 func inlvar(var_ *ir.Name) *ir.Name {
1288         if base.Flag.LowerM > 3 {
1289                 fmt.Printf("inlvar %+v\n", var_)
1290         }
1291
1292         n := typecheck.NewName(var_.Sym())
1293         n.SetType(var_.Type())
1294         n.SetTypecheck(1)
1295         n.Class = ir.PAUTO
1296         n.SetUsed(true)
1297         n.SetAutoTemp(var_.AutoTemp())
1298         n.Curfn = ir.CurFunc // the calling function, not the called one
1299         n.SetAddrtaken(var_.Addrtaken())
1300
1301         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1302         return n
1303 }
1304
1305 // Synthesize a variable to store the inlined function's results in.
1306 func retvar(t *types.Field, i int) *ir.Name {
1307         n := typecheck.NewName(typecheck.LookupNum("~R", i))
1308         n.SetType(t.Type)
1309         n.SetTypecheck(1)
1310         n.Class = ir.PAUTO
1311         n.SetUsed(true)
1312         n.Curfn = ir.CurFunc // the calling function, not the called one
1313         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1314         return n
1315 }
1316
1317 // The inlsubst type implements the actual inlining of a single
1318 // function call.
1319 type inlsubst struct {
1320         // Target of the goto substituted in place of a return.
1321         retlabel *types.Sym
1322
1323         // Temporary result variables.
1324         retvars []ir.Node
1325
1326         inlvars map[*ir.Name]*ir.Name
1327         // defnMarker is used to mark a Node for reassignment.
1328         // inlsubst.clovar set this during creating new ONAME.
1329         // inlsubst.node will set the correct Defn for inlvar.
1330         defnMarker ir.NilExpr
1331
1332         // bases maps from original PosBase to PosBase with an extra
1333         // inlined call frame.
1334         bases map[*src.PosBase]*src.PosBase
1335
1336         // newInlIndex is the index of the inlined call frame to
1337         // insert for inlined nodes.
1338         newInlIndex int
1339
1340         edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
1341
1342         // If non-nil, we are inside a closure inside the inlined function, and
1343         // newclofn is the Func of the new inlined closure.
1344         newclofn *ir.Func
1345
1346         fn *ir.Func // For debug -- the func that is being inlined
1347
1348         // If true, then don't update source positions during substitution
1349         // (retain old source positions).
1350         noPosUpdate bool
1351 }
1352
1353 // list inlines a list of nodes.
1354 func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
1355         s := make([]ir.Node, 0, len(ll))
1356         for _, n := range ll {
1357                 s = append(s, subst.node(n))
1358         }
1359         return s
1360 }
1361
1362 // fields returns a list of the fields of a struct type representing receiver,
1363 // params, or results, after duplicating the field nodes and substituting the
1364 // Nname nodes inside the field nodes.
1365 func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
1366         oldfields := oldt.FieldSlice()
1367         newfields := make([]*types.Field, len(oldfields))
1368         for i := range oldfields {
1369                 newfields[i] = oldfields[i].Copy()
1370                 if oldfields[i].Nname != nil {
1371                         newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
1372                 }
1373         }
1374         return newfields
1375 }
1376
1377 // clovar creates a new ONAME node for a local variable or param of a closure
1378 // inside a function being inlined.
1379 func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
1380         m := ir.NewNameAt(n.Pos(), n.Sym())
1381         m.Class = n.Class
1382         m.SetType(n.Type())
1383         m.SetTypecheck(1)
1384         if n.IsClosureVar() {
1385                 m.SetIsClosureVar(true)
1386         }
1387         if n.Addrtaken() {
1388                 m.SetAddrtaken(true)
1389         }
1390         if n.Used() {
1391                 m.SetUsed(true)
1392         }
1393         m.Defn = n.Defn
1394
1395         m.Curfn = subst.newclofn
1396
1397         switch defn := n.Defn.(type) {
1398         case nil:
1399                 // ok
1400         case *ir.Name:
1401                 if !n.IsClosureVar() {
1402                         base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
1403                 }
1404                 if n.Sym().Pkg != types.LocalPkg {
1405                         // If the closure came from inlining a function from
1406                         // another package, must change package of captured
1407                         // variable to localpkg, so that the fields of the closure
1408                         // struct are local package and can be accessed even if
1409                         // name is not exported. If you disable this code, you can
1410                         // reproduce the problem by running 'go test
1411                         // go/internal/srcimporter'. TODO(mdempsky) - maybe change
1412                         // how we create closure structs?
1413                         m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
1414                 }
1415                 // Make sure any inlvar which is the Defn
1416                 // of an ONAME closure var is rewritten
1417                 // during inlining. Don't substitute
1418                 // if Defn node is outside inlined function.
1419                 if subst.inlvars[n.Defn.(*ir.Name)] != nil {
1420                         m.Defn = subst.node(n.Defn)
1421                 }
1422         case *ir.AssignStmt, *ir.AssignListStmt:
1423                 // Mark node for reassignment at the end of inlsubst.node.
1424                 m.Defn = &subst.defnMarker
1425         case *ir.TypeSwitchGuard:
1426                 // TODO(mdempsky): Set m.Defn properly. See discussion on #45743.
1427         case *ir.RangeStmt:
1428                 // TODO: Set m.Defn properly if we support inlining range statement in the future.
1429         default:
1430                 base.FatalfAt(n.Pos(), "unexpected Defn: %+v", defn)
1431         }
1432
1433         if n.Outer != nil {
1434                 // Either the outer variable is defined in function being inlined,
1435                 // and we will replace it with the substituted variable, or it is
1436                 // defined outside the function being inlined, and we should just
1437                 // skip the outer variable (the closure variable of the function
1438                 // being inlined).
1439                 s := subst.node(n.Outer).(*ir.Name)
1440                 if s == n.Outer {
1441                         s = n.Outer.Outer
1442                 }
1443                 m.Outer = s
1444         }
1445         return m
1446 }
1447
1448 // closure does the necessary substitions for a ClosureExpr n and returns the new
1449 // closure node.
1450 func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
1451         // Prior to the subst edit, set a flag in the inlsubst to indicate
1452         // that we don't want to update the source positions in the new
1453         // closure function. If we do this, it will appear that the
1454         // closure itself has things inlined into it, which is not the
1455         // case. See issue #46234 for more details. At the same time, we
1456         // do want to update the position in the new ClosureExpr (which is
1457         // part of the function we're working on). See #49171 for an
1458         // example of what happens if we miss that update.
1459         newClosurePos := subst.updatedPos(n.Pos())
1460         defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate)
1461         subst.noPosUpdate = true
1462
1463         //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
1464
1465         oldfn := n.Func
1466         newfn := ir.NewClosureFunc(oldfn.Pos(), true)
1467
1468         if subst.newclofn != nil {
1469                 //fmt.Printf("Inlining a closure with a nested closure\n")
1470         }
1471         prevxfunc := subst.newclofn
1472
1473         // Mark that we are now substituting within a closure (within the
1474         // inlined function), and create new nodes for all the local
1475         // vars/params inside this closure.
1476         subst.newclofn = newfn
1477         newfn.Dcl = nil
1478         newfn.ClosureVars = nil
1479         for _, oldv := range oldfn.Dcl {
1480                 newv := subst.clovar(oldv)
1481                 subst.inlvars[oldv] = newv
1482                 newfn.Dcl = append(newfn.Dcl, newv)
1483         }
1484         for _, oldv := range oldfn.ClosureVars {
1485                 newv := subst.clovar(oldv)
1486                 subst.inlvars[oldv] = newv
1487                 newfn.ClosureVars = append(newfn.ClosureVars, newv)
1488         }
1489
1490         // Need to replace ONAME nodes in
1491         // newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
1492         oldt := oldfn.Type()
1493         newrecvs := subst.fields(oldt.Recvs())
1494         var newrecv *types.Field
1495         if len(newrecvs) > 0 {
1496                 newrecv = newrecvs[0]
1497         }
1498         newt := types.NewSignature(oldt.Pkg(), newrecv,
1499                 nil, subst.fields(oldt.Params()), subst.fields(oldt.Results()))
1500
1501         newfn.Nname.SetType(newt)
1502         newfn.Body = subst.list(oldfn.Body)
1503
1504         // Remove the nodes for the current closure from subst.inlvars
1505         for _, oldv := range oldfn.Dcl {
1506                 delete(subst.inlvars, oldv)
1507         }
1508         for _, oldv := range oldfn.ClosureVars {
1509                 delete(subst.inlvars, oldv)
1510         }
1511         // Go back to previous closure func
1512         subst.newclofn = prevxfunc
1513
1514         // Actually create the named function for the closure, now that
1515         // the closure is inlined in a specific function.
1516         newclo := newfn.OClosure
1517         newclo.SetPos(newClosurePos)
1518         newclo.SetInit(subst.list(n.Init()))
1519         return typecheck.Expr(newclo)
1520 }
1521
1522 // node recursively copies a node from the saved pristine body of the
1523 // inlined function, substituting references to input/output
1524 // parameters with ones to the tmpnames, and substituting returns with
1525 // assignments to the output.
1526 func (subst *inlsubst) node(n ir.Node) ir.Node {
1527         if n == nil {
1528                 return nil
1529         }
1530
1531         switch n.Op() {
1532         case ir.ONAME:
1533                 n := n.(*ir.Name)
1534
1535                 // Handle captured variables when inlining closures.
1536                 if n.IsClosureVar() && subst.newclofn == nil {
1537                         o := n.Outer
1538
1539                         // Deal with case where sequence of closures are inlined.
1540                         // TODO(danscales) - write test case to see if we need to
1541                         // go up multiple levels.
1542                         if o.Curfn != ir.CurFunc {
1543                                 o = o.Outer
1544                         }
1545
1546                         // make sure the outer param matches the inlining location
1547                         if o == nil || o.Curfn != ir.CurFunc {
1548                                 base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
1549                         }
1550
1551                         if base.Flag.LowerM > 2 {
1552                                 fmt.Printf("substituting captured name %+v  ->  %+v\n", n, o)
1553                         }
1554                         return o
1555                 }
1556
1557                 if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
1558                         if base.Flag.LowerM > 2 {
1559                                 fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
1560                         }
1561                         return inlvar
1562                 }
1563
1564                 if base.Flag.LowerM > 2 {
1565                         fmt.Printf("not substituting name %+v\n", n)
1566                 }
1567                 return n
1568
1569         case ir.OMETHEXPR:
1570                 n := n.(*ir.SelectorExpr)
1571                 return n
1572
1573         case ir.OLITERAL, ir.ONIL, ir.OTYPE:
1574                 // If n is a named constant or type, we can continue
1575                 // using it in the inline copy. Otherwise, make a copy
1576                 // so we can update the line number.
1577                 if n.Sym() != nil {
1578                         return n
1579                 }
1580
1581         case ir.ORETURN:
1582                 if subst.newclofn != nil {
1583                         // Don't do special substitutions if inside a closure
1584                         break
1585                 }
1586                 // Because of the above test for subst.newclofn,
1587                 // this return is guaranteed to belong to the current inlined function.
1588                 n := n.(*ir.ReturnStmt)
1589                 init := subst.list(n.Init())
1590                 if len(subst.retvars) != 0 && len(n.Results) != 0 {
1591                         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
1592
1593                         // Make a shallow copy of retvars.
1594                         // Otherwise OINLCALL.Rlist will be the same list,
1595                         // and later walk and typecheck may clobber it.
1596                         for _, n := range subst.retvars {
1597                                 as.Lhs.Append(n)
1598                         }
1599                         as.Rhs = subst.list(n.Results)
1600
1601                         if subst.fn.Inl.CanDelayResults {
1602                                 for _, n := range as.Lhs {
1603                                         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
1604                                         n.Name().Defn = as
1605                                 }
1606                         }
1607
1608                         init = append(init, typecheck.Stmt(as))
1609                 }
1610                 init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
1611                 typecheck.Stmts(init)
1612                 return ir.NewBlockStmt(base.Pos, init)
1613
1614         case ir.OGOTO, ir.OBREAK, ir.OCONTINUE:
1615                 if subst.newclofn != nil {
1616                         // Don't do special substitutions if inside a closure
1617                         break
1618                 }
1619                 n := n.(*ir.BranchStmt)
1620                 m := ir.Copy(n).(*ir.BranchStmt)
1621                 m.SetPos(subst.updatedPos(m.Pos()))
1622                 m.SetInit(nil)
1623                 m.Label = translateLabel(n.Label)
1624                 return m
1625
1626         case ir.OLABEL:
1627                 if subst.newclofn != nil {
1628                         // Don't do special substitutions if inside a closure
1629                         break
1630                 }
1631                 n := n.(*ir.LabelStmt)
1632                 m := ir.Copy(n).(*ir.LabelStmt)
1633                 m.SetPos(subst.updatedPos(m.Pos()))
1634                 m.SetInit(nil)
1635                 m.Label = translateLabel(n.Label)
1636                 return m
1637
1638         case ir.OCLOSURE:
1639                 return subst.closure(n.(*ir.ClosureExpr))
1640
1641         }
1642
1643         m := ir.Copy(n)
1644         m.SetPos(subst.updatedPos(m.Pos()))
1645         ir.EditChildren(m, subst.edit)
1646
1647         if subst.newclofn == nil {
1648                 // Translate any label on FOR, RANGE loops, SWITCH or SELECT
1649                 switch m.Op() {
1650                 case ir.OFOR:
1651                         m := m.(*ir.ForStmt)
1652                         m.Label = translateLabel(m.Label)
1653                         return m
1654
1655                 case ir.ORANGE:
1656                         m := m.(*ir.RangeStmt)
1657                         m.Label = translateLabel(m.Label)
1658                         return m
1659
1660                 case ir.OSWITCH:
1661                         m := m.(*ir.SwitchStmt)
1662                         m.Label = translateLabel(m.Label)
1663                         return m
1664
1665                 case ir.OSELECT:
1666                         m := m.(*ir.SelectStmt)
1667                         m.Label = translateLabel(m.Label)
1668                         return m
1669                 }
1670         }
1671
1672         switch m := m.(type) {
1673         case *ir.AssignStmt:
1674                 if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
1675                         lhs.Defn = m
1676                 }
1677         case *ir.AssignListStmt:
1678                 for _, lhs := range m.Lhs {
1679                         if lhs, ok := lhs.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
1680                                 lhs.Defn = m
1681                         }
1682                 }
1683         }
1684
1685         return m
1686 }
1687
1688 // translateLabel makes a label from an inlined function (if non-nil) be unique by
1689 // adding "·inlgen".
1690 func translateLabel(l *types.Sym) *types.Sym {
1691         if l == nil {
1692                 return nil
1693         }
1694         p := fmt.Sprintf("%s·%d", l.Name, inlgen)
1695         return typecheck.Lookup(p)
1696 }
1697
1698 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
1699         if subst.noPosUpdate {
1700                 return xpos
1701         }
1702         pos := base.Ctxt.PosTable.Pos(xpos)
1703         oldbase := pos.Base() // can be nil
1704         newbase := subst.bases[oldbase]
1705         if newbase == nil {
1706                 newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
1707                 subst.bases[oldbase] = newbase
1708         }
1709         pos.SetBase(newbase)
1710         return base.Ctxt.PosTable.XPos(pos)
1711 }
1712
1713 func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
1714         s := make([]*ir.Name, 0, len(ll))
1715         for _, n := range ll {
1716                 if n.Class == ir.PAUTO {
1717                         if !vis.usedLocals.Has(n) {
1718                                 continue
1719                         }
1720                 }
1721                 s = append(s, n)
1722         }
1723         return s
1724 }
1725
1726 // numNonClosures returns the number of functions in list which are not closures.
1727 func numNonClosures(list []*ir.Func) int {
1728         count := 0
1729         for _, fn := range list {
1730                 if fn.OClosure == nil {
1731                         count++
1732                 }
1733         }
1734         return count
1735 }
1736
1737 func doList(list []ir.Node, do func(ir.Node) bool) bool {
1738         for _, x := range list {
1739                 if x != nil {
1740                         if do(x) {
1741                                 return true
1742                         }
1743                 }
1744         }
1745         return false
1746 }
1747
1748 // isIndexingCoverageCounter returns true if the specified node 'n' is indexing
1749 // into a coverage counter array.
1750 func isIndexingCoverageCounter(n ir.Node) bool {
1751         if n.Op() != ir.OINDEX {
1752                 return false
1753         }
1754         ixn := n.(*ir.IndexExpr)
1755         if ixn.X.Op() != ir.ONAME || !ixn.X.Type().IsArray() {
1756                 return false
1757         }
1758         nn := ixn.X.(*ir.Name)
1759         return nn.CoverageCounter()
1760 }
1761
1762 // isAtomicCoverageCounterUpdate examines the specified node to
1763 // determine whether it represents a call to sync/atomic.AddUint32 to
1764 // increment a coverage counter.
1765 func isAtomicCoverageCounterUpdate(cn *ir.CallExpr) bool {
1766         if cn.X.Op() != ir.ONAME {
1767                 return false
1768         }
1769         name := cn.X.(*ir.Name)
1770         if name.Class != ir.PFUNC {
1771                 return false
1772         }
1773         fn := name.Sym().Name
1774         if name.Sym().Pkg.Path != "sync/atomic" ||
1775                 (fn != "AddUint32" && fn != "StoreUint32") {
1776                 return false
1777         }
1778         if len(cn.Args) != 2 || cn.Args[0].Op() != ir.OADDR {
1779                 return false
1780         }
1781         adn := cn.Args[0].(*ir.AddrExpr)
1782         v := isIndexingCoverageCounter(adn.X)
1783         return v
1784 }