]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/inline/inlheur/analyze_func_callsites.go
cmd/compile/internal/inlheur: regionalize call site analysis
[gostls13.git] / src / cmd / compile / internal / inline / inlheur / analyze_func_callsites.go
index b3422216afd97a60c88bb2ace59ef34876884174..67b97df7ce85dca7e55002b3bf6afb3fad827d89 100644 (file)
@@ -23,22 +23,25 @@ type callSiteAnalyzer struct {
        isInit   bool
 }
 
-func makeCallSiteAnalyzer(fn *ir.Func, ptab map[ir.Node]pstate) *callSiteAnalyzer {
+func makeCallSiteAnalyzer(fn *ir.Func, ptab map[ir.Node]pstate, loopNestingLevel int) *callSiteAnalyzer {
        isInit := fn.IsPackageInit() || strings.HasPrefix(fn.Sym().Name, "init.")
        return &callSiteAnalyzer{
-               fn:     fn,
-               cstab:  make(CallSiteTab),
-               ptab:   ptab,
-               isInit: isInit,
+               fn:       fn,
+               cstab:    make(CallSiteTab),
+               ptab:     ptab,
+               isInit:   isInit,
+               loopNest: loopNestingLevel,
+               nstack:   []ir.Node{fn},
        }
 }
 
-func computeCallSiteTable(fn *ir.Func, ptab map[ir.Node]pstate) CallSiteTab {
-       if debugTrace != 0 {
-               fmt.Fprintf(os.Stderr, "=-= making callsite table for func %v:\n",
-                       fn.Sym().Name)
-       }
-       csa := makeCallSiteAnalyzer(fn, ptab)
+// computeCallSiteTable builds and returns a table of call sites for
+// the specified region in function fn. A region here corresponds to a
+// specific subtree within the AST for a function. The main intended
+// use cases are for 'region' to be either A) an entire function body,
+// or B) an inlined call expression.
+func computeCallSiteTable(fn *ir.Func, region ir.Nodes, ptab map[ir.Node]pstate, loopNestingLevel int) CallSiteTab {
+       csa := makeCallSiteAnalyzer(fn, ptab, loopNestingLevel)
        var doNode func(ir.Node) bool
        doNode = func(n ir.Node) bool {
                csa.nodeVisitPre(n)
@@ -46,7 +49,9 @@ func computeCallSiteTable(fn *ir.Func, ptab map[ir.Node]pstate) CallSiteTab {
                csa.nodeVisitPost(n)
                return false
        }
-       doNode(fn)
+       for _, n := range region {
+               doNode(n)
+       }
        return csa.cstab
 }
 
@@ -152,8 +157,8 @@ func (csa *callSiteAnalyzer) addCallSite(callee *ir.Func, call *ir.CallExpr) {
 }
 
 // ScoreCalls assigns numeric scores to each of the callsites in
-// function 'fn'; the lower the score, the more helpful we think it
-// will be to inline.
+// function fn; the lower the score, the more helpful we think it will
+// be to inline.
 //
 // Unlike a lot of the other inline heuristics machinery, callsite
 // scoring can't be done as part of the CanInline call for a function,
@@ -176,17 +181,31 @@ func ScoreCalls(fn *ir.Func) {
                fmt.Fprintf(os.Stderr, "=-= ScoreCalls(%v)\n", ir.FuncName(fn))
        }
 
-       fih, ok := fpmap[fn]
+       funcInlHeur, ok := fpmap[fn]
        if !ok {
                // TODO: add an assert/panic here.
                return
        }
+       scoreCallsRegion(fn, fn.Body, funcInlHeur.cstab)
+}
+
+// scoreCallsRegion assigns numeric scores to each of the callsites in
+// region 'region' within function 'fn'. This can be called on
+// an entire function, or with 'region' set to a chunk of
+// code corresponding to an inlined call.
+func scoreCallsRegion(fn *ir.Func, region ir.Nodes, cstab CallSiteTab) {
+       if debugTrace&debugTraceScoring != 0 {
+               fmt.Fprintf(os.Stderr, "=-= scoreCallsRegion(%v, %s)\n",
+                       ir.FuncName(fn), region[0].Op().String())
+       }
+
+       resultNameTab := make(map[*ir.Name]resultPropAndCS)
 
        // Sort callsites to avoid any surprises with non deterministic
        // map iteration order (this is probably not needed, but here just
        // in case).
-       csl := make([]*CallSite, 0, len(fih.cstab))
-       for _, cs := range fih.cstab {
+       csl := make([]*CallSite, 0, len(cstab))
+       for _, cs := range cstab {
                csl = append(csl, cs)
        }
        sort.Slice(csl, func(i, j int) bool {
@@ -198,8 +217,8 @@ func ScoreCalls(fn *ir.Func) {
                var cprops *FuncProps
                fihcprops := false
                desercprops := false
-               if fih, ok := fpmap[cs.Callee]; ok {
-                       cprops = fih.props
+               if funcInlHeur, ok := fpmap[cs.Callee]; ok {
+                       cprops = funcInlHeur.props
                        fihcprops = true
                } else if cs.Callee.Inl != nil {
                        cprops = DeserializeFromString(cs.Callee.Inl.Properties)
@@ -214,10 +233,14 @@ func ScoreCalls(fn *ir.Func) {
                }
                cs.Score, cs.ScoreMask = computeCallSiteScore(cs.Callee, cprops, cs.Call, cs.Flags)
 
+               examineCallResults(cs, resultNameTab)
+
                if debugTrace&debugTraceScoring != 0 {
-                       fmt.Fprintf(os.Stderr, "=-= scoring call at %s: flags=%d score=%d fih=%v deser=%v\n", fmtFullPos(cs.Call.Pos()), cs.Flags, cs.Score, fihcprops, desercprops)
+                       fmt.Fprintf(os.Stderr, "=-= examineCallResults at %s: flags=%d score=%d funcInlHeur=%v deser=%v\n", fmtFullPos(cs.Call.Pos()), cs.Flags, cs.Score, fihcprops, desercprops)
                }
        }
+
+       rescoreBasedOnCallResultUses(fn, resultNameTab, cstab)
 }
 
 func (csa *callSiteAnalyzer) nodeVisitPre(n ir.Node) {
@@ -228,7 +251,7 @@ func (csa *callSiteAnalyzer) nodeVisitPre(n ir.Node) {
                }
        case ir.OCALLFUNC:
                ce := n.(*ir.CallExpr)
-               callee := pgo.DirectCallee(ce.X)
+               callee := pgo.DirectCallee(ce.Fun)
                if callee != nil && callee.Inl != nil {
                        csa.addCallSite(callee, ce)
                }
@@ -290,12 +313,12 @@ func hasTopLevelLoopBodyReturnOrBreak(loopBody ir.Nodes) bool {
 //
 // Here the top-level assignment statement for the foo() call is the
 // statement assigning to "x"; the top-level assignment for "bar()"
-// call is the assignment to x,y.   For the baz() and blah() calls,
+// call is the assignment to x,y. For the baz() and blah() calls,
 // there is no top level assignment statement.
 //
-// The unstated goal here is that we want to use the containing assignment
-// to establish a connection between a given call and the variables
-// to which its results/returns are being assigned.
+// The unstated goal here is that we want to use the containing
+// assignment to establish a connection between a given call and the
+// variables to which its results/returns are being assigned.
 //
 // Note that for the "bar" command above, the front end sometimes
 // decomposes this into two assignments, the first one assigning the