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)
csa.nodeVisitPost(n)
return false
}
- doNode(fn)
+ for _, n := range region {
+ doNode(n)
+ }
return csa.cstab
}
}
// 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,
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 {
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)
}
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) {
}
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)
}
//
// 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