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