1
2
3
4
5 package inlheur
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/types"
11 "fmt"
12 "os"
13 )
14
15
16
17
18
19 type funcFlagsAnalyzer struct {
20 fn *ir.Func
21 nstate map[ir.Node]pstate
22 noInfo bool
23 }
24
25
26
27 type pstate int
28
29 const (
30 psNoInfo pstate = iota
31 psCallsPanic
32 psMayReturn
33 psTop
34 )
35
36 func makeFuncFlagsAnalyzer(fn *ir.Func) *funcFlagsAnalyzer {
37 return &funcFlagsAnalyzer{
38 fn: fn,
39 nstate: make(map[ir.Node]pstate),
40 }
41 }
42
43
44 func (ffa *funcFlagsAnalyzer) setResults(funcProps *FuncProps) {
45 var rv FuncPropBits
46 if !ffa.noInfo && ffa.stateForList(ffa.fn.Body) == psCallsPanic {
47 rv = FuncPropNeverReturns
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 if isMainMain(ffa.fn) {
64 rv &^= FuncPropNeverReturns
65 }
66 funcProps.Flags = rv
67 }
68
69 func (ffa *funcFlagsAnalyzer) getState(n ir.Node) pstate {
70 return ffa.nstate[n]
71 }
72
73 func (ffa *funcFlagsAnalyzer) setState(n ir.Node, st pstate) {
74 if st != psNoInfo {
75 ffa.nstate[n] = st
76 }
77 }
78
79 func (ffa *funcFlagsAnalyzer) updateState(n ir.Node, st pstate) {
80 if st == psNoInfo {
81 delete(ffa.nstate, n)
82 } else {
83 ffa.nstate[n] = st
84 }
85 }
86
87 func (ffa *funcFlagsAnalyzer) panicPathTable() map[ir.Node]pstate {
88 return ffa.nstate
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 func blockCombine(pred, succ pstate) pstate {
105 switch succ {
106 case psTop:
107 return pred
108 case psMayReturn:
109 if pred == psCallsPanic {
110 return psCallsPanic
111 }
112 return psMayReturn
113 case psNoInfo:
114 return pred
115 case psCallsPanic:
116 if pred == psMayReturn {
117 return psMayReturn
118 }
119 return psCallsPanic
120 }
121 panic("should never execute")
122 }
123
124
125
126 func branchCombine(p1, p2 pstate) pstate {
127 if p1 == psCallsPanic && p2 == psCallsPanic {
128 return psCallsPanic
129 }
130 if p1 == psMayReturn || p2 == psMayReturn {
131 return psMayReturn
132 }
133 return psNoInfo
134 }
135
136
137
138
139 func (ffa *funcFlagsAnalyzer) stateForList(list ir.Nodes) pstate {
140 st := psTop
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 for i := len(list) - 1; i >= 0; i-- {
156 n := list[i]
157 psi := ffa.getState(n)
158 if debugTrace&debugTraceFuncFlags != 0 {
159 fmt.Fprintf(os.Stderr, "=-= %v: stateForList n=%s ps=%s\n",
160 ir.Line(n), n.Op().String(), psi.String())
161 }
162 st = blockCombine(psi, st)
163 ffa.updateState(n, st)
164 }
165 if st == psTop {
166 st = psNoInfo
167 }
168 return st
169 }
170
171 func isMainMain(fn *ir.Func) bool {
172 s := fn.Sym()
173 return (s.Pkg.Name == "main" && s.Name == "main")
174 }
175
176 func isWellKnownFunc(s *types.Sym, pkg, name string) bool {
177 return s.Pkg.Path == pkg && s.Name == name
178 }
179
180
181
182 func isExitCall(n ir.Node) bool {
183 if n.Op() != ir.OCALLFUNC {
184 return false
185 }
186 cx := n.(*ir.CallExpr)
187 name := ir.StaticCalleeName(cx.Fun)
188 if name == nil {
189 return false
190 }
191 s := name.Sym()
192 if isWellKnownFunc(s, "os", "Exit") ||
193 isWellKnownFunc(s, "runtime", "throw") {
194 return true
195 }
196 if funcProps := propsForFunc(name.Func); funcProps != nil {
197 if funcProps.Flags&FuncPropNeverReturns != 0 {
198 return true
199 }
200 }
201 return name.Func.NeverReturns()
202 }
203
204
205
206 func (ffa *funcFlagsAnalyzer) pessimize() {
207 ffa.noInfo = true
208 }
209
210
211
212
213
214
215 func shouldVisit(n ir.Node) bool {
216 _, isStmt := n.(ir.Stmt)
217 return n.Op() != ir.ODCL &&
218 (isStmt || n.Op() == ir.OCALLFUNC || n.Op() == ir.OPANIC)
219 }
220
221
222
223
224 func (ffa *funcFlagsAnalyzer) nodeVisitPost(n ir.Node) {
225 if debugTrace&debugTraceFuncFlags != 0 {
226 fmt.Fprintf(os.Stderr, "=+= nodevis %v %s should=%v\n",
227 ir.Line(n), n.Op().String(), shouldVisit(n))
228 }
229 if !shouldVisit(n) {
230 return
231 }
232 var st pstate
233 switch n.Op() {
234 case ir.OCALLFUNC:
235 if isExitCall(n) {
236 st = psCallsPanic
237 }
238 case ir.OPANIC:
239 st = psCallsPanic
240 case ir.ORETURN:
241 st = psMayReturn
242 case ir.OBREAK, ir.OCONTINUE:
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258 st = psMayReturn
259 n := n.(*ir.BranchStmt)
260 if n.Label != nil {
261 ffa.pessimize()
262 }
263 case ir.OBLOCK:
264 n := n.(*ir.BlockStmt)
265 st = ffa.stateForList(n.List)
266 case ir.OCASE:
267 if ccst, ok := n.(*ir.CaseClause); ok {
268 st = ffa.stateForList(ccst.Body)
269 } else if ccst, ok := n.(*ir.CommClause); ok {
270 st = ffa.stateForList(ccst.Body)
271 } else {
272 panic("unexpected")
273 }
274 case ir.OIF:
275 n := n.(*ir.IfStmt)
276 st = branchCombine(ffa.stateForList(n.Body), ffa.stateForList(n.Else))
277 case ir.OFOR:
278
279
280 n := n.(*ir.ForStmt)
281 bst := ffa.stateForList(n.Body)
282 if n.Cond == nil {
283 st = bst
284 } else {
285 if bst == psMayReturn {
286 st = psMayReturn
287 }
288 }
289 case ir.ORANGE:
290
291 n := n.(*ir.RangeStmt)
292 if ffa.stateForList(n.Body) == psMayReturn {
293 st = psMayReturn
294 }
295 case ir.OGOTO:
296
297
298 ffa.pessimize()
299 case ir.OSELECT:
300
301
302 n := n.(*ir.SelectStmt)
303 if len(n.Cases) != 0 {
304 st = psTop
305 for _, c := range n.Cases {
306 st = branchCombine(ffa.stateForList(c.Body), st)
307 }
308 }
309 case ir.OSWITCH:
310 n := n.(*ir.SwitchStmt)
311 if len(n.Cases) != 0 {
312 st = psTop
313 for _, c := range n.Cases {
314 st = branchCombine(ffa.stateForList(c.Body), st)
315 }
316 }
317
318 st, fall := psTop, psNoInfo
319 for i := len(n.Cases) - 1; i >= 0; i-- {
320 cas := n.Cases[i]
321 cst := ffa.stateForList(cas.Body)
322 endsInFallthrough := false
323 if len(cas.Body) != 0 {
324 endsInFallthrough = cas.Body[0].Op() == ir.OFALL
325 }
326 if endsInFallthrough {
327 cst = blockCombine(cst, fall)
328 }
329 st = branchCombine(st, cst)
330 fall = cst
331 }
332 case ir.OFALL:
333
334 case ir.ODCLFUNC, ir.ORECOVER, ir.OAS, ir.OAS2, ir.OAS2FUNC, ir.OASOP,
335 ir.OPRINTLN, ir.OPRINT, ir.OLABEL, ir.OCALLINTER, ir.ODEFER,
336 ir.OSEND, ir.ORECV, ir.OSELRECV2, ir.OGO, ir.OAPPEND, ir.OAS2DOTTYPE,
337 ir.OAS2MAPR, ir.OGETG, ir.ODELETE, ir.OINLMARK, ir.OAS2RECV,
338 ir.OMIN, ir.OMAX, ir.OMAKE, ir.ORECOVERFP, ir.OGETCALLERSP:
339
340 case ir.OTAILCALL, ir.OJUMPTABLE, ir.OTYPESW:
341
342 base.Fatalf("unexpected op %s in func %s",
343 n.Op().String(), ir.FuncName(ffa.fn))
344 default:
345 base.Fatalf("%v: unhandled op %s in func %v",
346 ir.Line(n), n.Op().String(), ir.FuncName(ffa.fn))
347 }
348 if debugTrace&debugTraceFuncFlags != 0 {
349 fmt.Fprintf(os.Stderr, "=-= %v: visit n=%s returns %s\n",
350 ir.Line(n), n.Op().String(), st.String())
351 }
352 ffa.setState(n, st)
353 }
354
355 func (ffa *funcFlagsAnalyzer) nodeVisitPre(n ir.Node) {
356 }
357
View as plain text