...
Source file src/pkg/cmd/compile/internal/ssa/deadstore.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/src"
10 )
11
12
13
14
15
16 func dse(f *Func) {
17 var stores []*Value
18 loadUse := f.newSparseSet(f.NumValues())
19 defer f.retSparseSet(loadUse)
20 storeUse := f.newSparseSet(f.NumValues())
21 defer f.retSparseSet(storeUse)
22 shadowed := f.newSparseMap(f.NumValues())
23 defer f.retSparseMap(shadowed)
24 for _, b := range f.Blocks {
25
26
27
28 loadUse.clear()
29 storeUse.clear()
30 stores = stores[:0]
31 for _, v := range b.Values {
32 if v.Op == OpPhi {
33
34 continue
35 }
36 if v.Type.IsMemory() {
37 stores = append(stores, v)
38 for _, a := range v.Args {
39 if a.Block == b && a.Type.IsMemory() {
40 storeUse.add(a.ID)
41 if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef && v.Op != OpVarKill {
42
43
44 loadUse.add(a.ID)
45 }
46 }
47 }
48 } else {
49 for _, a := range v.Args {
50 if a.Block == b && a.Type.IsMemory() {
51 loadUse.add(a.ID)
52 }
53 }
54 }
55 }
56 if len(stores) == 0 {
57 continue
58 }
59
60
61 var last *Value
62 for _, v := range stores {
63 if storeUse.contains(v.ID) {
64 continue
65 }
66 if last != nil {
67 b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
68 }
69 last = v
70 }
71 if last == nil {
72 b.Fatalf("no last store found - cycle?")
73 }
74
75
76
77
78
79 shadowed.clear()
80 v := last
81
82 walkloop:
83 if loadUse.contains(v.ID) {
84
85
86 shadowed.clear()
87 }
88 if v.Op == OpStore || v.Op == OpZero {
89 var sz int64
90 if v.Op == OpStore {
91 sz = v.Aux.(*types.Type).Size()
92 } else {
93 sz = v.AuxInt
94 }
95 if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
96
97 if v.Op == OpStore {
98
99 v.SetArgs1(v.Args[2])
100 } else {
101
102 typesz := v.Args[0].Type.Elem().Size()
103 if sz != typesz {
104 f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
105 sz, typesz, v.LongString())
106 }
107 v.SetArgs1(v.Args[1])
108 }
109 v.Aux = nil
110 v.AuxInt = 0
111 v.Op = OpCopy
112 } else {
113 if sz > 0x7fffffff {
114 sz = 0x7fffffff
115 }
116 shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
117 }
118 }
119
120 if v.Op == OpPhi {
121
122
123
124
125 continue
126 }
127 for _, a := range v.Args {
128 if a.Block == b && a.Type.IsMemory() {
129 v = a
130 goto walkloop
131 }
132 }
133 }
134 }
135
136
137
138
139
140 func elimDeadAutosGeneric(f *Func) {
141 addr := make(map[*Value]GCNode)
142 elim := make(map[*Value]GCNode)
143 used := make(map[GCNode]bool)
144
145
146 visit := func(v *Value) (changed bool) {
147 args := v.Args
148 switch v.Op {
149 case OpAddr, OpLocalAddr:
150
151 n, ok := v.Aux.(GCNode)
152 if !ok || n.StorageClass() != ClassAuto {
153 return
154 }
155 if addr[v] == nil {
156 addr[v] = n
157 changed = true
158 }
159 return
160 case OpVarDef, OpVarKill:
161
162 n, ok := v.Aux.(GCNode)
163 if !ok || n.StorageClass() != ClassAuto {
164 return
165 }
166 if elim[v] == nil {
167 elim[v] = n
168 changed = true
169 }
170 return
171 case OpVarLive:
172
173 n, ok := v.Aux.(GCNode)
174 if !ok || n.StorageClass() != ClassAuto {
175 return
176 }
177 if !used[n] {
178 used[n] = true
179 changed = true
180 }
181 return
182 case OpStore, OpMove, OpZero:
183
184 n, ok := addr[args[0]]
185 if ok && elim[v] == nil {
186 elim[v] = n
187 changed = true
188 }
189
190 args = args[1:]
191 }
192
193
194
195
196 if v.Op.SymEffect() != SymNone && v.Op != OpArg {
197 panic("unhandled op with sym effect")
198 }
199
200 if v.Uses == 0 && v.Op != OpNilCheck || len(args) == 0 {
201
202 return
203 }
204
205
206
207
208 if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == OpPhi || v.MemoryArg() != nil {
209 for _, a := range args {
210 if n, ok := addr[a]; ok {
211 if !used[n] {
212 used[n] = true
213 changed = true
214 }
215 }
216 }
217 return
218 }
219
220
221 node := GCNode(nil)
222 for _, a := range args {
223 if n, ok := addr[a]; ok && !used[n] {
224 if node == nil {
225 node = n
226 } else if node != n {
227
228
229
230
231
232 used[n] = true
233 changed = true
234 }
235 }
236 }
237 if node == nil {
238 return
239 }
240 if addr[v] == nil {
241
242 addr[v] = node
243 changed = true
244 return
245 }
246 if addr[v] != node {
247
248 used[node] = true
249 changed = true
250 }
251 return
252 }
253
254 iterations := 0
255 for {
256 if iterations == 4 {
257
258 return
259 }
260 iterations++
261 changed := false
262 for _, b := range f.Blocks {
263 for _, v := range b.Values {
264 changed = visit(v) || changed
265 }
266
267 if b.Control == nil {
268 continue
269 }
270 if n, ok := addr[b.Control]; ok && !used[n] {
271 used[n] = true
272 changed = true
273 }
274 }
275 if !changed {
276 break
277 }
278 }
279
280
281 for v, n := range elim {
282 if used[n] {
283 continue
284 }
285
286 v.SetArgs1(v.MemoryArg())
287 v.Aux = nil
288 v.AuxInt = 0
289 v.Op = OpCopy
290 }
291 }
292
293
294
295 func elimUnreadAutos(f *Func) {
296
297
298
299 seen := make(map[GCNode]bool)
300 var stores []*Value
301 for _, b := range f.Blocks {
302 for _, v := range b.Values {
303 n, ok := v.Aux.(GCNode)
304 if !ok {
305 continue
306 }
307 if n.StorageClass() != ClassAuto {
308 continue
309 }
310
311 effect := v.Op.SymEffect()
312 switch effect {
313 case SymNone, SymWrite:
314
315
316
317 if !seen[n] {
318 stores = append(stores, v)
319 }
320 default:
321
322
323
324
325
326 if v.Uses > 0 {
327 seen[n] = true
328 }
329 }
330 }
331 }
332
333
334 for _, store := range stores {
335 n, _ := store.Aux.(GCNode)
336 if seen[n] {
337 continue
338 }
339
340
341 store.SetArgs1(store.MemoryArg())
342 store.Aux = nil
343 store.AuxInt = 0
344 store.Op = OpCopy
345 }
346 }
347
View as plain text