1
2
3
4
5 package inlheur
6
7 import (
8 "cmd/compile/internal/ir"
9 "fmt"
10 "os"
11 )
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 type resultPropAndCS struct {
35 defcs *CallSite
36 props ResultPropBits
37 }
38
39 type resultUseAnalyzer struct {
40 resultNameTab map[*ir.Name]resultPropAndCS
41 fn *ir.Func
42 cstab CallSiteTab
43 *condLevelTracker
44 }
45
46
47
48
49 func (csa *callSiteAnalyzer) rescoreBasedOnCallResultUses(fn *ir.Func, resultNameTab map[*ir.Name]resultPropAndCS, cstab CallSiteTab) {
50 enableDebugTraceIfEnv()
51 rua := &resultUseAnalyzer{
52 resultNameTab: resultNameTab,
53 fn: fn,
54 cstab: cstab,
55 condLevelTracker: new(condLevelTracker),
56 }
57 var doNode func(ir.Node) bool
58 doNode = func(n ir.Node) bool {
59 rua.nodeVisitPre(n)
60 ir.DoChildren(n, doNode)
61 rua.nodeVisitPost(n)
62 return false
63 }
64 doNode(fn)
65 disableDebugTrace()
66 }
67
68 func (csa *callSiteAnalyzer) examineCallResults(cs *CallSite, resultNameTab map[*ir.Name]resultPropAndCS) map[*ir.Name]resultPropAndCS {
69 if debugTrace&debugTraceScoring != 0 {
70 fmt.Fprintf(os.Stderr, "=-= examining call results for %q\n",
71 EncodeCallSiteKey(cs))
72 }
73
74
75
76
77
78
79
80 names, autoTemps, props := namesDefined(cs)
81 if len(names) == 0 {
82 return resultNameTab
83 }
84
85 if debugTrace&debugTraceScoring != 0 {
86 fmt.Fprintf(os.Stderr, "=-= %d names defined\n", len(names))
87 }
88
89
90
91
92
93 const interesting = (ResultIsConcreteTypeConvertedToInterface |
94 ResultAlwaysSameConstant | ResultAlwaysSameInlinableFunc | ResultAlwaysSameFunc)
95 for idx, n := range names {
96 rprop := props.ResultFlags[idx]
97
98 if debugTrace&debugTraceScoring != 0 {
99 fmt.Fprintf(os.Stderr, "=-= props for ret %d %q: %s\n",
100 idx, n.Sym().Name, rprop.String())
101 }
102
103 if rprop&interesting == 0 {
104 continue
105 }
106 if csa.nameFinder.reassigned(n) {
107 continue
108 }
109 if resultNameTab == nil {
110 resultNameTab = make(map[*ir.Name]resultPropAndCS)
111 } else if _, ok := resultNameTab[n]; ok {
112 panic("should never happen")
113 }
114 entry := resultPropAndCS{
115 defcs: cs,
116 props: rprop,
117 }
118 resultNameTab[n] = entry
119 if autoTemps[idx] != nil {
120 resultNameTab[autoTemps[idx]] = entry
121 }
122 if debugTrace&debugTraceScoring != 0 {
123 fmt.Fprintf(os.Stderr, "=-= add resultNameTab table entry n=%v autotemp=%v props=%s\n", n, autoTemps[idx], rprop.String())
124 }
125 }
126 return resultNameTab
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 func namesDefined(cs *CallSite) ([]*ir.Name, []*ir.Name, *FuncProps) {
148
149
150 if cs.Assign == nil {
151 return nil, nil, nil
152 }
153 funcInlHeur, ok := fpmap[cs.Callee]
154 if !ok {
155
156 return nil, nil, nil
157 }
158 if len(funcInlHeur.props.ResultFlags) == 0 {
159 return nil, nil, nil
160 }
161
162
163 if len(funcInlHeur.props.ResultFlags) == 1 {
164 asgn, ok := cs.Assign.(*ir.AssignStmt)
165 if !ok {
166 return nil, nil, nil
167 }
168
169 aname, ok := asgn.X.(*ir.Name)
170 if !ok {
171 return nil, nil, nil
172 }
173 return []*ir.Name{aname}, []*ir.Name{nil}, funcInlHeur.props
174 }
175
176
177 asgn, ok := cs.Assign.(*ir.AssignListStmt)
178 if !ok || !asgn.Def {
179 return nil, nil, nil
180 }
181 userVars := make([]*ir.Name, len(funcInlHeur.props.ResultFlags))
182 autoTemps := make([]*ir.Name, len(funcInlHeur.props.ResultFlags))
183 for idx, x := range asgn.Lhs {
184 if n, ok := x.(*ir.Name); ok {
185 userVars[idx] = n
186 r := asgn.Rhs[idx]
187 if r.Op() == ir.OCONVNOP {
188 r = r.(*ir.ConvExpr).X
189 }
190 if ir.IsAutoTmp(r) {
191 autoTemps[idx] = r.(*ir.Name)
192 }
193 if debugTrace&debugTraceScoring != 0 {
194 fmt.Fprintf(os.Stderr, "=-= multi-ret namedef uv=%v at=%v\n",
195 x, autoTemps[idx])
196 }
197 } else {
198 return nil, nil, nil
199 }
200 }
201 return userVars, autoTemps, funcInlHeur.props
202 }
203
204 func (rua *resultUseAnalyzer) nodeVisitPost(n ir.Node) {
205 rua.condLevelTracker.post(n)
206 }
207
208 func (rua *resultUseAnalyzer) nodeVisitPre(n ir.Node) {
209 rua.condLevelTracker.pre(n)
210 switch n.Op() {
211 case ir.OCALLINTER:
212 if debugTrace&debugTraceScoring != 0 {
213 fmt.Fprintf(os.Stderr, "=-= rescore examine iface call %v:\n", n)
214 }
215 rua.callTargetCheckResults(n)
216 case ir.OCALLFUNC:
217 if debugTrace&debugTraceScoring != 0 {
218 fmt.Fprintf(os.Stderr, "=-= rescore examine call %v:\n", n)
219 }
220 rua.callTargetCheckResults(n)
221 case ir.OIF:
222 ifst := n.(*ir.IfStmt)
223 rua.foldCheckResults(ifst.Cond)
224 case ir.OSWITCH:
225 swst := n.(*ir.SwitchStmt)
226 if swst.Tag != nil {
227 rua.foldCheckResults(swst.Tag)
228 }
229
230 }
231 }
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 func (rua *resultUseAnalyzer) callTargetCheckResults(call ir.Node) {
251 ce := call.(*ir.CallExpr)
252 rname := rua.getCallResultName(ce)
253 if rname == nil {
254 return
255 }
256 if debugTrace&debugTraceScoring != 0 {
257 fmt.Fprintf(os.Stderr, "=-= staticvalue returns %v:\n",
258 rname)
259 }
260 if rname.Class != ir.PAUTO {
261 return
262 }
263 switch call.Op() {
264 case ir.OCALLINTER:
265 if debugTrace&debugTraceScoring != 0 {
266 fmt.Fprintf(os.Stderr, "=-= in %s checking %v for cci prop:\n",
267 rua.fn.Sym().Name, rname)
268 }
269 if cs := rua.returnHasProp(rname, ResultIsConcreteTypeConvertedToInterface); cs != nil {
270
271 adj := returnFeedsConcreteToInterfaceCallAdj
272 cs.Score, cs.ScoreMask = adjustScore(adj, cs.Score, cs.ScoreMask)
273 }
274 case ir.OCALLFUNC:
275 if debugTrace&debugTraceScoring != 0 {
276 fmt.Fprintf(os.Stderr, "=-= in %s checking %v for samefunc props:\n",
277 rua.fn.Sym().Name, rname)
278 v, ok := rua.resultNameTab[rname]
279 if !ok {
280 fmt.Fprintf(os.Stderr, "=-= no entry for %v in rt\n", rname)
281 } else {
282 fmt.Fprintf(os.Stderr, "=-= props for %v: %q\n", rname, v.props.String())
283 }
284 }
285 if cs := rua.returnHasProp(rname, ResultAlwaysSameInlinableFunc); cs != nil {
286 adj := returnFeedsInlinableFuncToIndCallAdj
287 cs.Score, cs.ScoreMask = adjustScore(adj, cs.Score, cs.ScoreMask)
288 } else if cs := rua.returnHasProp(rname, ResultAlwaysSameFunc); cs != nil {
289 adj := returnFeedsFuncToIndCallAdj
290 cs.Score, cs.ScoreMask = adjustScore(adj, cs.Score, cs.ScoreMask)
291
292 }
293 }
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 func (rua *resultUseAnalyzer) foldCheckResults(cond ir.Node) {
315 namesUsed := collectNamesUsed(cond)
316 if len(namesUsed) == 0 {
317 return
318 }
319 var cs *CallSite
320 for _, n := range namesUsed {
321 rpcs, found := rua.resultNameTab[n]
322 if !found {
323 return
324 }
325 if cs != nil && rpcs.defcs != cs {
326 return
327 }
328 cs = rpcs.defcs
329 if rpcs.props&ResultAlwaysSameConstant == 0 {
330 return
331 }
332 }
333 if debugTrace&debugTraceScoring != 0 {
334 nls := func(nl []*ir.Name) string {
335 r := ""
336 for _, n := range nl {
337 r += " " + n.Sym().Name
338 }
339 return r
340 }
341 fmt.Fprintf(os.Stderr, "=-= calling ShouldFoldIfNameConstant on names={%s} cond=%v\n", nls(namesUsed), cond)
342 }
343
344 if !ShouldFoldIfNameConstant(cond, namesUsed) {
345 return
346 }
347 adj := returnFeedsConstToIfAdj
348 cs.Score, cs.ScoreMask = adjustScore(adj, cs.Score, cs.ScoreMask)
349 }
350
351 func collectNamesUsed(expr ir.Node) []*ir.Name {
352 res := []*ir.Name{}
353 ir.Visit(expr, func(n ir.Node) {
354 if n.Op() != ir.ONAME {
355 return
356 }
357 nn := n.(*ir.Name)
358 if nn.Class != ir.PAUTO {
359 return
360 }
361 res = append(res, nn)
362 })
363 return res
364 }
365
366 func (rua *resultUseAnalyzer) returnHasProp(name *ir.Name, prop ResultPropBits) *CallSite {
367 v, ok := rua.resultNameTab[name]
368 if !ok {
369 return nil
370 }
371 if v.props&prop == 0 {
372 return nil
373 }
374 return v.defcs
375 }
376
377 func (rua *resultUseAnalyzer) getCallResultName(ce *ir.CallExpr) *ir.Name {
378 var callTarg ir.Node
379 if sel, ok := ce.Fun.(*ir.SelectorExpr); ok {
380
381 callTarg = sel.X
382 } else if ctarg, ok := ce.Fun.(*ir.Name); ok {
383
384 callTarg = ctarg
385 } else {
386 return nil
387 }
388 r := ir.StaticValue(callTarg)
389 if debugTrace&debugTraceScoring != 0 {
390 fmt.Fprintf(os.Stderr, "=-= staticname on %v returns %v:\n",
391 callTarg, r)
392 }
393 if r.Op() == ir.OCALLFUNC {
394
395
396
397
398
399 ce := r.(*ir.CallExpr)
400 cs, ok := rua.cstab[ce]
401 if !ok {
402 return nil
403 }
404 names, _, _ := namesDefined(cs)
405 if len(names) == 0 {
406 return nil
407 }
408 return names[0]
409 } else if r.Op() == ir.ONAME {
410 return r.(*ir.Name)
411 }
412 return nil
413 }
414
View as plain text