package inlheur
import (
- "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/pgo"
"fmt"
"os"
- "sort"
"strings"
)
isInit bool
}
-func makeCallSiteAnalyzer(fn *ir.Func, ptab map[ir.Node]pstate) *callSiteAnalyzer {
+func makeCallSiteAnalyzer(fn *ir.Func, cstab CallSiteTab, 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: cstab,
+ 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, cstab CallSiteTab, ptab map[ir.Node]pstate, loopNestingLevel int) CallSiteTab {
+ csa := makeCallSiteAnalyzer(fn, cstab, ptab, loopNestingLevel)
var doNode func(ir.Node) bool
doNode = func(n ir.Node) bool {
csa.nodeVisitPre(n)
csa.nodeVisitPost(n)
return false
}
- doNode(fn)
+ for _, n := range region {
+ doNode(n)
+ }
return csa.cstab
}
cs.Score = int(callee.Inl.Cost)
}
+ if csa.cstab == nil {
+ csa.cstab = make(CallSiteTab)
+ }
csa.cstab[call] = cs
if debugTrace&debugTraceCalls != 0 {
- fmt.Fprintf(os.Stderr, "=-= added callsite: callee=%s call=%v\n",
- callee.Sym().Name, callee)
- }
-}
-
-// 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.
-//
-// Unlike a lot of the other inline heuristics machinery, callsite
-// scoring can't be done as part of the CanInline call for a function,
-// due to fact that we may be working on a non-trivial SCC. So for
-// example with this SCC:
-//
-// func foo(x int) { func bar(x int, f func()) {
-// if x != 0 { f()
-// bar(x, func(){}) foo(x-1)
-// } }
-// }
-//
-// We don't want to perform scoring for the 'foo' call in "bar" until
-// after foo has been analyzed, but it's conceivable that CanInline
-// might visit bar before foo for this SCC.
-func ScoreCalls(fn *ir.Func) {
- enableDebugTraceIfEnv()
- defer disableDebugTrace()
- if debugTrace&debugTraceScoring != 0 {
- fmt.Fprintf(os.Stderr, "=-= ScoreCalls(%v)\n", ir.FuncName(fn))
- }
-
- fih, ok := fpmap[fn]
- if !ok {
- // TODO: add an assert/panic here.
- return
+ fmt.Fprintf(os.Stderr, "=-= added callsite at %s: callee=%s call[%p]=%v\n", fmtFullPos(call.Pos()), callee.Sym().Name, call, call)
}
-
- 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 = append(csl, cs)
- }
- sort.Slice(csl, func(i, j int) bool {
- return csl[i].ID < csl[j].ID
- })
-
- // Score each call site.
- for _, cs := range csl {
- var cprops *FuncProps
- fihcprops := false
- desercprops := false
- if fih, ok := fpmap[cs.Callee]; ok {
- cprops = fih.props
- fihcprops = true
- } else if cs.Callee.Inl != nil {
- cprops = DeserializeFromString(cs.Callee.Inl.Properties)
- desercprops = true
- } else {
- if base.Debug.DumpInlFuncProps != "" {
- fmt.Fprintf(os.Stderr, "=-= *** unable to score call to %s from %s\n", cs.Callee.Sym().Name, fmtFullPos(cs.Call.Pos()))
- panic("should never happen")
- } else {
- continue
- }
- }
- 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)
- }
- }
-
- rescoreBasedOnCallResultUses(fn, resultNameTab, fih.cstab)
}
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)
}