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
}
}
func (csa *callSiteAnalyzer) addCallSite(callee *ir.Func, call *ir.CallExpr) {
+ flags := csa.flagsForNode(call)
// FIXME: maybe bulk-allocate these?
cs := &CallSite{
Call: call,
Callee: callee,
Assign: csa.containingAssignment(call),
- Flags: csa.flagsForNode(call),
- Id: uint(len(csa.cstab)),
+ Flags: flags,
+ ID: uint(len(csa.cstab)),
}
if _, ok := csa.cstab[call]; ok {
fmt.Fprintf(os.Stderr, "*** cstab duplicate entry at: %s\n",
fmt.Fprintf(os.Stderr, "*** call: %+v\n", call)
panic("bad")
}
- if debugTrace&debugTraceCalls != 0 {
- fmt.Fprintf(os.Stderr, "=-= added callsite: callee=%s call=%v\n",
- callee.Sym().Name, callee)
+ if callee.Inl != nil {
+ // Set initial score for callsite to the cost computed
+ // by CanInline; this score will be refined later based
+ // on heuristics.
+ 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 at %s: callee=%s call[%p]=%v\n", fmtFullPos(call.Pos()), callee.Sym().Name, call, call)
+ }
}
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