...
1
2
3
4
5 package ir
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/types"
10 )
11
12
13
14
15
16
17
18
19
20 type ReassignOracle struct {
21 fn *Func
22
23
24 singleDef map[*Name]Node
25
26
27
28
29
30
31
32
33 funcAssigns map[*Name][]*AssignStmt
34 }
35
36
37
38
39
40 func (ro *ReassignOracle) Init(fn *Func) {
41 ro.fn = fn
42
43
44
45 ro.singleDef = make(map[*Name]Node)
46 ro.funcAssigns = make(map[*Name][]*AssignStmt)
47 sig := fn.Type()
48 numParams := sig.NumRecvs() + sig.NumParams()
49 for _, param := range fn.Dcl[:numParams] {
50 if IsBlank(param) {
51 continue
52 }
53
54 ro.singleDef[param] = fn
55 }
56
57
58
59 var findLocals func(n Node) bool
60 findLocals = func(n Node) bool {
61 if nn, ok := n.(*Name); ok {
62 if nn.Class == PAUTO && !nn.Addrtaken() {
63 isFunc := nn.Type().Kind() == types.TFUNC
64 if nn.Defn == nil {
65
66 if isFunc {
67 ro.funcAssigns[nn] = nil
68 }
69 } else if _, ok := nn.Defn.(*AssignStmt); ok {
70 ro.singleDef[nn] = nn.Defn
71 if isFunc {
72 ro.funcAssigns[nn] = nil
73 }
74 } else {
75 ro.singleDef[nn] = nn.Defn
76 }
77 }
78 } else if nn, ok := n.(*ClosureExpr); ok {
79 Any(nn.Func, findLocals)
80 }
81 return false
82 }
83 Any(fn, findLocals)
84
85 outerName := func(x Node) *Name {
86 if x == nil {
87 return nil
88 }
89 n, ok := OuterValue(x).(*Name)
90 if ok {
91 return n.Canonical()
92 }
93 return nil
94 }
95
96
97
98
99
100 pruneIfNeeded := func(nn Node, asn Node) {
101 oname := outerName(nn)
102 if oname == nil {
103 return
104 }
105 if defn, ok := ro.singleDef[oname]; ok {
106
107 paramAssigned := oname.Class == PPARAM
108
109 localAssigned := (oname.Class == PAUTO && asn != defn)
110 if paramAssigned || localAssigned {
111
112
113
114 delete(ro.singleDef, oname)
115 }
116 }
117 if _, ok := ro.funcAssigns[oname]; ok {
118 as, isOAS := asn.(*AssignStmt)
119 if isOAS && isNilAssign(as) {
120
121 } else if !isOAS {
122
123 delete(ro.funcAssigns, oname)
124 } else {
125 ro.funcAssigns[oname] = append(ro.funcAssigns[oname], as)
126 }
127 }
128 }
129
130
131
132
133 var do func(n Node) bool
134 do = func(n Node) bool {
135 switch n.Op() {
136 case OAS:
137 asn := n.(*AssignStmt)
138 pruneIfNeeded(asn.X, n)
139 case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:
140 asn := n.(*AssignListStmt)
141 for _, p := range asn.Lhs {
142 pruneIfNeeded(p, n)
143 }
144 case OASOP:
145 asn := n.(*AssignOpStmt)
146 pruneIfNeeded(asn.X, n)
147 case ORANGE:
148 rs := n.(*RangeStmt)
149 pruneIfNeeded(rs.Key, n)
150 pruneIfNeeded(rs.Value, n)
151 case OCLOSURE:
152 n := n.(*ClosureExpr)
153 Any(n.Func, do)
154 }
155 return false
156 }
157 Any(fn, do)
158 }
159
160
161
162 func (ro *ReassignOracle) StaticValue(n Node) Node {
163 arg := n
164 for {
165 if n.Op() == OCONVNOP {
166 n = n.(*ConvExpr).X
167 continue
168 }
169
170 if n.Op() == OINLCALL {
171 n = n.(*InlinedCallExpr).SingleResult()
172 continue
173 }
174
175 if n.Op() == OPAREN {
176 n = n.(*ParenExpr).X
177 continue
178 }
179
180 n1 := ro.staticValue1(n)
181 if n1 == nil {
182 if consistencyCheckEnabled {
183 checkStaticValueResult(arg, n)
184 }
185 return n
186 }
187 n = n1
188 }
189 }
190
191 func (ro *ReassignOracle) staticValue1(nn Node) Node {
192 if nn.Op() != ONAME {
193 return nil
194 }
195 n := nn.(*Name).Canonical()
196 if n.Class != PAUTO {
197 return nil
198 }
199
200 defn := n.Defn
201 if defn == nil {
202 return nil
203 }
204
205 var rhs Node
206 FindRHS:
207 switch defn.Op() {
208 case OAS:
209 defn := defn.(*AssignStmt)
210 rhs = defn.Y
211 case OAS2:
212 defn := defn.(*AssignListStmt)
213 for i, lhs := range defn.Lhs {
214 if lhs == n {
215 rhs = defn.Rhs[i]
216 break FindRHS
217 }
218 }
219 base.FatalfAt(defn.Pos(), "%v missing from LHS of %v", n, defn)
220 default:
221 return nil
222 }
223 if rhs == nil {
224 base.FatalfAt(defn.Pos(), "RHS is nil: %v", defn)
225 }
226
227 if _, ok := ro.singleDef[n]; !ok {
228 return nil
229 }
230
231 return rhs
232 }
233
234
235
236 func (ro *ReassignOracle) Reassigned(n *Name) bool {
237 _, ok := ro.singleDef[n]
238 result := !ok
239 if consistencyCheckEnabled {
240 checkReassignedResult(n, result)
241 }
242 return result
243 }
244
245
246
247
248
249
250
251
252 func (ro *ReassignOracle) FuncAssignments(name *Name) []*AssignStmt {
253 return ro.funcAssigns[name.Canonical()]
254 }
255
256
257 func isNilAssign(as *AssignStmt) bool {
258 if as.Y == nil {
259 return true
260 }
261 y := as.Y
262 for y.Op() == OCONVNOP {
263 y = y.(*ConvExpr).X
264 }
265 return IsNil(y)
266 }
267
View as plain text