1
2
3
4
5 package inlheur
6
7 import (
8 "cmd/compile/internal/ir"
9 "fmt"
10 "go/constant"
11 "go/token"
12 "os"
13 )
14
15
16
17
18 type resultsAnalyzer struct {
19 fname string
20 props []ResultPropBits
21 values []resultVal
22 inlineMaxBudget int
23 *nameFinder
24 }
25
26
27
28
29
30
31 type resultVal struct {
32 cval constant.Value
33 fn *ir.Name
34 fnClo bool
35 top bool
36 derived bool
37 }
38
39
40
41
42
43
44 func addResultsAnalyzer(fn *ir.Func, analyzers []propAnalyzer, fp *FuncProps, inlineMaxBudget int, nf *nameFinder) []propAnalyzer {
45 ra, props := makeResultsAnalyzer(fn, inlineMaxBudget, nf)
46 if ra != nil {
47 analyzers = append(analyzers, ra)
48 } else {
49 fp.ResultFlags = props
50 }
51 return analyzers
52 }
53
54
55
56
57
58 func makeResultsAnalyzer(fn *ir.Func, inlineMaxBudget int, nf *nameFinder) (*resultsAnalyzer, []ResultPropBits) {
59 results := fn.Type().Results()
60 if len(results) == 0 {
61 return nil, nil
62 }
63 props := make([]ResultPropBits, len(results))
64 if fn.Inl == nil {
65 return nil, props
66 }
67 vals := make([]resultVal, len(results))
68 interestingToAnalyze := false
69 for i := range results {
70 rt := results[i].Type
71 if !rt.IsScalar() && !rt.HasNil() {
72
73
74 continue
75 }
76
77
78 vals[i].top = true
79 interestingToAnalyze = true
80 }
81 if !interestingToAnalyze {
82 return nil, props
83 }
84 ra := &resultsAnalyzer{
85 props: props,
86 values: vals,
87 inlineMaxBudget: inlineMaxBudget,
88 nameFinder: nf,
89 }
90 return ra, nil
91 }
92
93
94
95 func (ra *resultsAnalyzer) setResults(funcProps *FuncProps) {
96
97 for i := range ra.values {
98 if ra.props[i] == ResultAlwaysSameFunc && !ra.values[i].derived {
99 f := ra.values[i].fn.Func
100
101
102
103
104
105
106
107 if f.Inl != nil && f.Inl.Cost <= int32(ra.inlineMaxBudget) {
108 ra.props[i] = ResultAlwaysSameInlinableFunc
109 }
110 }
111 }
112 funcProps.ResultFlags = ra.props
113 }
114
115 func (ra *resultsAnalyzer) pessimize() {
116 for i := range ra.props {
117 ra.props[i] = ResultNoInfo
118 }
119 }
120
121 func (ra *resultsAnalyzer) nodeVisitPre(n ir.Node) {
122 }
123
124 func (ra *resultsAnalyzer) nodeVisitPost(n ir.Node) {
125 if len(ra.values) == 0 {
126 return
127 }
128 if n.Op() != ir.ORETURN {
129 return
130 }
131 if debugTrace&debugTraceResults != 0 {
132 fmt.Fprintf(os.Stderr, "=+= returns nodevis %v %s\n",
133 ir.Line(n), n.Op().String())
134 }
135
136
137
138 rs := n.(*ir.ReturnStmt)
139 if len(rs.Results) != len(ra.values) {
140 ra.pessimize()
141 return
142 }
143 for i, r := range rs.Results {
144 ra.analyzeResult(i, r)
145 }
146 }
147
148
149
150
151
152
153
154 func (ra *resultsAnalyzer) analyzeResult(ii int, n ir.Node) {
155 isAllocMem := ra.isAllocatedMem(n)
156 isConcConvItf := ra.isConcreteConvIface(n)
157 constVal := ra.constValue(n)
158 isConst := (constVal != nil)
159 isNil := ra.isNil(n)
160 rfunc := ra.funcName(n)
161 isFunc := (rfunc != nil)
162 isClo := (rfunc != nil && rfunc.Func.OClosure != nil)
163 curp := ra.props[ii]
164 dprops, isDerivedFromCall := ra.deriveReturnFlagsFromCallee(n)
165 newp := ResultNoInfo
166 var newcval constant.Value
167 var newfunc *ir.Name
168
169 if debugTrace&debugTraceResults != 0 {
170 fmt.Fprintf(os.Stderr, "=-= %v: analyzeResult n=%s ismem=%v isconcconv=%v isconst=%v isnil=%v isfunc=%v isclo=%v\n", ir.Line(n), n.Op().String(), isAllocMem, isConcConvItf, isConst, isNil, isFunc, isClo)
171 }
172
173 if ra.values[ii].top {
174 ra.values[ii].top = false
175
176
177 switch {
178 case isAllocMem:
179 newp = ResultIsAllocatedMem
180 case isConcConvItf:
181 newp = ResultIsConcreteTypeConvertedToInterface
182 case isFunc:
183 newp = ResultAlwaysSameFunc
184 newfunc = rfunc
185 case isConst:
186 newp = ResultAlwaysSameConstant
187 newcval = constVal
188 case isNil:
189 newp = ResultAlwaysSameConstant
190 newcval = nil
191 case isDerivedFromCall:
192 newp = dprops
193 ra.values[ii].derived = true
194 }
195 } else {
196 if !ra.values[ii].derived {
197
198
199
200
201 switch curp {
202 case ResultIsAllocatedMem:
203 if isAllocMem {
204 newp = ResultIsAllocatedMem
205 }
206 case ResultIsConcreteTypeConvertedToInterface:
207 if isConcConvItf {
208 newp = ResultIsConcreteTypeConvertedToInterface
209 }
210 case ResultAlwaysSameConstant:
211 if isNil && ra.values[ii].cval == nil {
212 newp = ResultAlwaysSameConstant
213 newcval = nil
214 } else if isConst && constant.Compare(constVal, token.EQL, ra.values[ii].cval) {
215 newp = ResultAlwaysSameConstant
216 newcval = constVal
217 }
218 case ResultAlwaysSameFunc:
219 if isFunc && isSameFuncName(rfunc, ra.values[ii].fn) {
220 newp = ResultAlwaysSameFunc
221 newfunc = rfunc
222 }
223 }
224 }
225 }
226 ra.values[ii].fn = newfunc
227 ra.values[ii].fnClo = isClo
228 ra.values[ii].cval = newcval
229 ra.props[ii] = newp
230
231 if debugTrace&debugTraceResults != 0 {
232 fmt.Fprintf(os.Stderr, "=-= %v: analyzeResult newp=%s\n",
233 ir.Line(n), newp)
234 }
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 func (ra *resultsAnalyzer) deriveReturnFlagsFromCallee(n ir.Node) (ResultPropBits, bool) {
254 if n.Op() != ir.OCALLFUNC {
255 return 0, false
256 }
257 ce := n.(*ir.CallExpr)
258 if ce.Fun.Op() != ir.ONAME {
259 return 0, false
260 }
261 called := ir.StaticValue(ce.Fun)
262 if called.Op() != ir.ONAME {
263 return 0, false
264 }
265 cname := ra.funcName(called)
266 if cname == nil {
267 return 0, false
268 }
269 calleeProps := propsForFunc(cname.Func)
270 if calleeProps == nil {
271 return 0, false
272 }
273 if len(calleeProps.ResultFlags) != 1 {
274 return 0, false
275 }
276 return calleeProps.ResultFlags[0], true
277 }
278
View as plain text