|
5 | 5 | package inlheur
|
6 | 6 |
|
7 | 7 | import (
|
| 8 | + "cmd/compile/internal/base" |
8 | 9 | "cmd/compile/internal/ir"
|
9 | 10 | "cmd/compile/internal/pgo"
|
10 | 11 | "fmt"
|
11 | 12 | "os"
|
| 13 | + "sort" |
12 | 14 | "strings"
|
13 | 15 | )
|
14 | 16 |
|
@@ -120,26 +122,102 @@ func (csa *callSiteAnalyzer) determinePanicPathBits(call ir.Node, r CSPropBits)
|
120 | 122 | }
|
121 | 123 |
|
122 | 124 | func (csa *callSiteAnalyzer) addCallSite(callee *ir.Func, call *ir.CallExpr) {
|
| 125 | + flags := csa.flagsForNode(call) |
123 | 126 | // FIXME: maybe bulk-allocate these?
|
124 | 127 | cs := &CallSite{
|
125 | 128 | Call: call,
|
126 | 129 | Callee: callee,
|
127 | 130 | Assign: csa.containingAssignment(call),
|
128 |
| - Flags: csa.flagsForNode(call), |
129 |
| - Id: uint(len(csa.cstab)), |
| 131 | + Flags: flags, |
| 132 | + ID: uint(len(csa.cstab)), |
130 | 133 | }
|
131 | 134 | if _, ok := csa.cstab[call]; ok {
|
132 | 135 | fmt.Fprintf(os.Stderr, "*** cstab duplicate entry at: %s\n",
|
133 | 136 | fmtFullPos(call.Pos()))
|
134 | 137 | fmt.Fprintf(os.Stderr, "*** call: %+v\n", call)
|
135 | 138 | panic("bad")
|
136 | 139 | }
|
| 140 | + if callee.Inl != nil { |
| 141 | + // Set initial score for callsite to the cost computed |
| 142 | + // by CanInline; this score will be refined later based |
| 143 | + // on heuristics. |
| 144 | + cs.Score = int(callee.Inl.Cost) |
| 145 | + } |
| 146 | + |
| 147 | + csa.cstab[call] = cs |
137 | 148 | if debugTrace&debugTraceCalls != 0 {
|
138 | 149 | fmt.Fprintf(os.Stderr, "=-= added callsite: callee=%s call=%v\n",
|
139 | 150 | callee.Sym().Name, callee)
|
140 | 151 | }
|
| 152 | +} |
141 | 153 |
|
142 |
| - csa.cstab[call] = cs |
| 154 | +// ScoreCalls assigns numeric scores to each of the callsites in |
| 155 | +// function 'fn'; the lower the score, the more helpful we think it |
| 156 | +// will be to inline. |
| 157 | +// |
| 158 | +// Unlike a lot of the other inline heuristics machinery, callsite |
| 159 | +// scoring can't be done as part of the CanInline call for a function, |
| 160 | +// due to fact that we may be working on a non-trivial SCC. So for |
| 161 | +// example with this SCC: |
| 162 | +// |
| 163 | +// func foo(x int) { func bar(x int, f func()) { |
| 164 | +// if x != 0 { f() |
| 165 | +// bar(x, func(){}) foo(x-1) |
| 166 | +// } } |
| 167 | +// } |
| 168 | +// |
| 169 | +// We don't want to perform scoring for the 'foo' call in "bar" until |
| 170 | +// after foo has been analyzed, but it's conceivable that CanInline |
| 171 | +// might visit bar before foo for this SCC. |
| 172 | +func ScoreCalls(fn *ir.Func) { |
| 173 | + enableDebugTraceIfEnv() |
| 174 | + defer disableDebugTrace() |
| 175 | + if debugTrace&debugTraceScoring != 0 { |
| 176 | + fmt.Fprintf(os.Stderr, "=-= ScoreCalls(%v)\n", ir.FuncName(fn)) |
| 177 | + } |
| 178 | + |
| 179 | + fih, ok := fpmap[fn] |
| 180 | + if !ok { |
| 181 | + // TODO: add an assert/panic here. |
| 182 | + return |
| 183 | + } |
| 184 | + |
| 185 | + // Sort callsites to avoid any surprises with non deterministic |
| 186 | + // map iteration order (this is probably not needed, but here just |
| 187 | + // in case). |
| 188 | + csl := make([]*CallSite, 0, len(fih.cstab)) |
| 189 | + for _, cs := range fih.cstab { |
| 190 | + csl = append(csl, cs) |
| 191 | + } |
| 192 | + sort.Slice(csl, func(i, j int) bool { |
| 193 | + return csl[i].ID < csl[j].ID |
| 194 | + }) |
| 195 | + |
| 196 | + // Score each call site. |
| 197 | + for _, cs := range csl { |
| 198 | + var cprops *FuncProps |
| 199 | + fihcprops := false |
| 200 | + desercprops := false |
| 201 | + if fih, ok := fpmap[cs.Callee]; ok { |
| 202 | + cprops = fih.props |
| 203 | + fihcprops = true |
| 204 | + } else if cs.Callee.Inl != nil { |
| 205 | + cprops = DeserializeFromString(cs.Callee.Inl.Properties) |
| 206 | + desercprops = true |
| 207 | + } else { |
| 208 | + if base.Debug.DumpInlFuncProps != "" { |
| 209 | + fmt.Fprintf(os.Stderr, "=-= *** unable to score call to %s from %s\n", cs.Callee.Sym().Name, fmtFullPos(cs.Call.Pos())) |
| 210 | + panic("should never happen") |
| 211 | + } else { |
| 212 | + continue |
| 213 | + } |
| 214 | + } |
| 215 | + cs.Score, cs.ScoreMask = computeCallSiteScore(cs.Callee, cprops, cs.Call, cs.Flags) |
| 216 | + |
| 217 | + if debugTrace&debugTraceScoring != 0 { |
| 218 | + 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) |
| 219 | + } |
| 220 | + } |
143 | 221 | }
|
144 | 222 |
|
145 | 223 | func (csa *callSiteAnalyzer) nodeVisitPre(n ir.Node) {
|
|
0 commit comments