1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/ir"
9 "cmd/compile/internal/types"
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
25 localAddrs := map[any]*Value{}
26 for _, b := range f.Blocks {
27
28
29
30 loadUse.clear()
31 storeUse.clear()
32
33 for k := range localAddrs {
34 delete(localAddrs, k)
35 }
36 stores = stores[:0]
37 for _, v := range b.Values {
38 if v.Op == OpPhi {
39
40 continue
41 }
42 if v.Type.IsMemory() {
43 stores = append(stores, v)
44 for _, a := range v.Args {
45 if a.Block == b && a.Type.IsMemory() {
46 storeUse.add(a.ID)
47 if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef {
48
49
50 loadUse.add(a.ID)
51 }
52 }
53 }
54 } else {
55 if v.Op == OpLocalAddr {
56 if _, ok := localAddrs[v.Aux]; !ok {
57 localAddrs[v.Aux] = v
58 } else {
59 continue
60 }
61 }
62 for _, a := range v.Args {
63 if a.Block == b && a.Type.IsMemory() {
64 loadUse.add(a.ID)
65 }
66 }
67 }
68 }
69 if len(stores) == 0 {
70 continue
71 }
72
73
74 var last *Value
75 for _, v := range stores {
76 if storeUse.contains(v.ID) {
77 continue
78 }
79 if last != nil {
80 b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
81 }
82 last = v
83 }
84 if last == nil {
85 b.Fatalf("no last store found - cycle?")
86 }
87
88
89
90
91
92
93
94 shadowed.clear()
95 v := last
96
97 walkloop:
98 if loadUse.contains(v.ID) {
99
100
101 shadowed.clear()
102 }
103 if v.Op == OpStore || v.Op == OpZero {
104 ptr := v.Args[0]
105 var off int64
106 for ptr.Op == OpOffPtr {
107 off += ptr.AuxInt
108 ptr = ptr.Args[0]
109 }
110 var sz int64
111 if v.Op == OpStore {
112 sz = v.Aux.(*types.Type).Size()
113 } else {
114 sz = v.AuxInt
115 }
116 if ptr.Op == OpLocalAddr {
117 if la, ok := localAddrs[ptr.Aux]; ok {
118 ptr = la
119 }
120 }
121 sr := shadowRange(shadowed.get(ptr.ID))
122 if sr.contains(off, off+sz) {
123
124
125 if v.Op == OpStore {
126
127 v.SetArgs1(v.Args[2])
128 } else {
129
130 v.SetArgs1(v.Args[1])
131 }
132 v.Aux = nil
133 v.AuxInt = 0
134 v.Op = OpCopy
135 } else {
136
137 shadowed.set(ptr.ID, int32(sr.merge(off, off+sz)))
138 }
139 }
140
141 if v.Op == OpPhi {
142
143
144
145
146 continue
147 }
148 for _, a := range v.Args {
149 if a.Block == b && a.Type.IsMemory() {
150 v = a
151 goto walkloop
152 }
153 }
154 }
155 }
156
157
158
159
160
161
162 type shadowRange int32
163
164 func (sr shadowRange) lo() int64 {
165 return int64(sr & 0xffff)
166 }
167
168 func (sr shadowRange) hi() int64 {
169 return int64((sr >> 16) & 0xffff)
170 }
171
172
173 func (sr shadowRange) contains(lo, hi int64) bool {
174 return lo >= sr.lo() && hi <= sr.hi()
175 }
176
177
178
179 func (sr shadowRange) merge(lo, hi int64) shadowRange {
180 if lo < 0 || hi > 0xffff {
181
182 return sr
183 }
184 if sr.lo() == sr.hi() {
185
186 return shadowRange(lo + hi<<16)
187 }
188 if hi < sr.lo() || lo > sr.hi() {
189
190
191
192 if sr.hi()-sr.lo() >= hi-lo {
193 return sr
194 }
195 return shadowRange(lo + hi<<16)
196 }
197
198 return shadowRange(min(lo, sr.lo()) + max(hi, sr.hi())<<16)
199 }
200
201
202
203
204
205 func elimDeadAutosGeneric(f *Func) {
206 addr := make(map[*Value]*ir.Name)
207 elim := make(map[*Value]*ir.Name)
208 var used ir.NameSet
209
210
211 visit := func(v *Value) (changed bool) {
212 args := v.Args
213 switch v.Op {
214 case OpAddr, OpLocalAddr:
215
216 n, ok := v.Aux.(*ir.Name)
217 if !ok || n.Class != ir.PAUTO {
218 return
219 }
220 if addr[v] == nil {
221 addr[v] = n
222 changed = true
223 }
224 return
225 case OpVarDef:
226
227 n, ok := v.Aux.(*ir.Name)
228 if !ok || n.Class != ir.PAUTO {
229 return
230 }
231 if elim[v] == nil {
232 elim[v] = n
233 changed = true
234 }
235 return
236 case OpVarLive:
237
238
239
240
241
242
243 n, ok := v.Aux.(*ir.Name)
244 if !ok || n.Class != ir.PAUTO {
245 return
246 }
247 if !used.Has(n) {
248 used.Add(n)
249 changed = true
250 }
251 return
252 case OpStore, OpMove, OpZero:
253
254 n, ok := addr[args[0]]
255 if ok && elim[v] == nil {
256 elim[v] = n
257 changed = true
258 }
259
260 args = args[1:]
261 }
262
263
264
265
266 if v.Op.SymEffect() != SymNone && v.Op != OpArg {
267 panic("unhandled op with sym effect")
268 }
269
270 if v.Uses == 0 && v.Op != OpNilCheck && !v.Op.IsCall() && !v.Op.HasSideEffects() || len(args) == 0 {
271
272
273 return
274 }
275
276
277
278
279 if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == OpPhi || v.MemoryArg() != nil {
280 for _, a := range args {
281 if n, ok := addr[a]; ok {
282 if !used.Has(n) {
283 used.Add(n)
284 changed = true
285 }
286 }
287 }
288 return
289 }
290
291
292 var node *ir.Name
293 for _, a := range args {
294 if n, ok := addr[a]; ok && !used.Has(n) {
295 if node == nil {
296 node = n
297 } else if node != n {
298
299
300
301
302
303 used.Add(n)
304 changed = true
305 }
306 }
307 }
308 if node == nil {
309 return
310 }
311 if addr[v] == nil {
312
313 addr[v] = node
314 changed = true
315 return
316 }
317 if addr[v] != node {
318
319 used.Add(node)
320 changed = true
321 }
322 return
323 }
324
325 iterations := 0
326 for {
327 if iterations == 4 {
328
329 return
330 }
331 iterations++
332 changed := false
333 for _, b := range f.Blocks {
334 for _, v := range b.Values {
335 changed = visit(v) || changed
336 }
337
338 for _, c := range b.ControlValues() {
339 if n, ok := addr[c]; ok && !used.Has(n) {
340 used.Add(n)
341 changed = true
342 }
343 }
344 }
345 if !changed {
346 break
347 }
348 }
349
350
351 for v, n := range elim {
352 if used.Has(n) {
353 continue
354 }
355
356 v.SetArgs1(v.MemoryArg())
357 v.Aux = nil
358 v.AuxInt = 0
359 v.Op = OpCopy
360 }
361 }
362
363
364
365 func elimUnreadAutos(f *Func) {
366
367
368
369 var seen ir.NameSet
370 var stores []*Value
371 for _, b := range f.Blocks {
372 for _, v := range b.Values {
373 n, ok := v.Aux.(*ir.Name)
374 if !ok {
375 continue
376 }
377 if n.Class != ir.PAUTO {
378 continue
379 }
380
381 effect := v.Op.SymEffect()
382 switch effect {
383 case SymNone, SymWrite:
384
385
386
387 if !seen.Has(n) {
388 stores = append(stores, v)
389 }
390 default:
391
392
393
394
395
396 if v.Uses > 0 {
397 seen.Add(n)
398 }
399 }
400 }
401 }
402
403
404 for _, store := range stores {
405 n, _ := store.Aux.(*ir.Name)
406 if seen.Has(n) {
407 continue
408 }
409
410
411 store.SetArgs1(store.MemoryArg())
412 store.Aux = nil
413 store.AuxInt = 0
414 store.Op = OpCopy
415 }
416 }
417
View as plain text