1
2
3
4
5 package ssacompile
6
7 import (
8 "cmd/compile/internal/ir"
9 "cmd/compile/internal/ssa"
10 "cmd/compile/internal/ssa/ssaop"
11 "cmd/compile/internal/types"
12 "cmd/internal/obj"
13 )
14
15
16
17 const maxShadowRanges = 64
18
19
20
21
22
23 func dse(f *ssa.Func) {
24 var stores []*ssa.Value
25 loadUse := f.NewSparseSet(f.NumValues())
26 defer f.RetSparseSet(loadUse)
27 storeUse := f.NewSparseSet(f.NumValues())
28 defer f.RetSparseSet(storeUse)
29 shadowed := f.NewSparseMap(f.NumValues())
30 defer f.RetSparseMap(shadowed)
31
32 localAddrs := map[any]*ssa.Value{}
33
34
35 var shadowedRanges []*shadowRanges
36
37 for _, b := range f.Blocks {
38
39
40
41 loadUse.Clear()
42 storeUse.Clear()
43 clear(localAddrs)
44 stores = stores[:0]
45 for _, v := range b.Values {
46 if v.Op == ssaop.OpPhi {
47
48 continue
49 }
50 if v.Type.IsMemory() {
51 stores = append(stores, v)
52 for _, a := range v.Args {
53 if a.Block == b && a.Type.IsMemory() {
54 storeUse.Add(a.ID)
55 switch v.Op {
56 case ssaop.OpStore, ssaop.OpZero, ssaop.OpVarDef:
57
58 case ssaop.OpMove:
59
60
61
62 if v.Args[1].Op == ssaop.OpAddr && ssa.SymIsRO(ssa.AuxToSym(v.Args[1].Aux)) {
63 break
64 }
65 fallthrough
66 default:
67
68
69 loadUse.Add(a.ID)
70 }
71 }
72 }
73 } else {
74 if v.Op == ssaop.OpLocalAddr {
75 if _, ok := localAddrs[v.Aux]; !ok {
76 localAddrs[v.Aux] = v
77 }
78 continue
79 }
80 if v.Op == ssaop.OpInlMark || v.Op == ssaop.OpConvert {
81
82 continue
83 }
84 for _, a := range v.Args {
85 if a.Block == b && a.Type.IsMemory() {
86 loadUse.Add(a.ID)
87 }
88 }
89 }
90 }
91 if len(stores) == 0 {
92 continue
93 }
94
95
96 var last *ssa.Value
97 for _, v := range stores {
98 if storeUse.Contains(v.ID) {
99 continue
100 }
101 if last != nil {
102 b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
103 }
104 last = v
105 }
106 if last == nil {
107 b.Fatalf("no last store found - cycle?")
108 }
109
110
111
112
113
114
115
116 shadowed.Clear()
117 shadowedRanges = shadowedRanges[:0]
118 v := last
119
120 walkloop:
121 if loadUse.Contains(v.ID) {
122
123
124 shadowed.Clear()
125 shadowedRanges = shadowedRanges[:0]
126 }
127 if v.Op == ssaop.OpStore || v.Op == ssaop.OpZero || v.Op == ssaop.OpMove {
128 ptr := v.Args[0]
129 var off int64
130 for ptr.Op == ssaop.OpOffPtr {
131 off += ptr.AuxInt
132 ptr = ptr.Args[0]
133 }
134 var sz int64
135 switch v.Op {
136 case ssaop.OpStore:
137 sz = v.Aux.(*types.Type).Size()
138 case ssaop.OpZero, ssaop.OpMove:
139 sz = v.AuxInt
140 }
141 if ptr.Op == ssaop.OpLocalAddr {
142 if la, ok := localAddrs[ptr.Aux]; ok {
143 ptr = la
144 }
145 }
146 var si *shadowRanges
147 idx, ok := shadowed.Get(ptr.ID)
148 if ok {
149
150 si = shadowedRanges[idx-1]
151 }
152
153 if si != nil && si.contains(off, off+sz) {
154
155
156 if v.Op == ssaop.OpStore || v.Op == ssaop.OpMove {
157
158
159 v.SetArgs1(v.Args[2])
160 } else {
161
162 v.SetArgs1(v.Args[1])
163 }
164 v.Aux = nil
165 v.AuxInt = 0
166 v.Op = ssaop.OpCopy
167 } else {
168
169 if si == nil {
170 si = &shadowRanges{}
171 shadowedRanges = append(shadowedRanges, si)
172
173 shadowed.Set(ptr.ID, int32(len(shadowedRanges)))
174 }
175 si.add(off, off+sz)
176 }
177 }
178
179 if v.Op == ssaop.OpPhi {
180
181
182
183
184 continue
185 }
186 for _, a := range v.Args {
187 if a.Block == b && a.Type.IsMemory() {
188 v = a
189 goto walkloop
190 }
191 }
192 }
193 }
194
195
196 type shadowRange struct {
197 lo, hi uint16
198 }
199
200
201 type shadowRanges struct {
202 ranges []shadowRange
203 }
204
205
206 func (sr *shadowRanges) contains(lo, hi int64) bool {
207 for _, r := range sr.ranges {
208 if lo >= int64(r.lo) && hi <= int64(r.hi) {
209 return true
210 }
211 }
212 return false
213 }
214
215 func (sr *shadowRanges) add(lo, hi int64) {
216
217
218
219
220 if lo < 0 || hi > 0xffff || len(sr.ranges) >= maxShadowRanges {
221 return
222 }
223 nlo := lo
224 nhi := hi
225 out := sr.ranges[:0]
226
227 for _, r := range sr.ranges {
228 if nhi < int64(r.lo) || nlo > int64(r.hi) {
229 out = append(out, r)
230 continue
231 }
232 if int64(r.lo) < nlo {
233 nlo = int64(r.lo)
234 }
235 if int64(r.hi) > nhi {
236 nhi = int64(r.hi)
237 }
238 }
239 sr.ranges = append(out, shadowRange{uint16(nlo), uint16(nhi)})
240 }
241
242
243
244
245
246 func elimDeadAutosGeneric(f *ssa.Func) {
247 addr := make(map[*ssa.Value]*ir.Name)
248 elim := make(map[*ssa.Value]*ir.Name)
249 move := make(map[*ir.Name]ir.NameSet)
250 var used ir.NameSet
251
252
253
254 var usedAdd func(n *ir.Name) bool
255 usedAdd = func(n *ir.Name) bool {
256 if used.Has(n) {
257 return false
258 }
259 used.Add(n)
260 if s := move[n]; s != nil {
261 delete(move, n)
262 for n := range s {
263 usedAdd(n)
264 }
265 }
266 return true
267 }
268
269
270 visit := func(v *ssa.Value) (changed bool) {
271 args := v.Args
272 switch v.Op {
273 case ssaop.OpAddr, ssaop.OpLocalAddr:
274
275 n, ok := v.Aux.(*ir.Name)
276 if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
277 return
278 }
279 if addr[v] == nil {
280 addr[v] = n
281 changed = true
282 }
283 return
284 case ssaop.OpVarDef:
285
286 n, ok := v.Aux.(*ir.Name)
287 if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
288 return
289 }
290 if elim[v] == nil {
291 elim[v] = n
292 changed = true
293 }
294 return
295 case ssaop.OpVarLive:
296
297
298
299
300
301
302 n, ok := v.Aux.(*ir.Name)
303 if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
304 return
305 }
306 changed = usedAdd(n) || changed
307 return
308 case ssaop.OpStore, ssaop.OpMove, ssaop.OpZero:
309
310 n, ok := addr[args[0]]
311 if ok && elim[v] == nil {
312 elim[v] = n
313 changed = true
314 }
315
316 args = args[1:]
317 }
318
319
320
321
322 if v.Op.SymEffect() != ssaop.SymNone && v.Op != ssaop.OpArg {
323 panic("unhandled op with sym effect")
324 }
325
326 if v.Uses == 0 && v.Op != ssaop.OpNilCheck && !v.Op.IsCall() && !v.Op.HasSideEffects() || len(args) == 0 {
327
328
329 return
330 }
331
332
333
334
335 if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == ssaop.OpPhi || v.MemoryArg() != nil {
336 for _, a := range args {
337 if n, ok := addr[a]; ok {
338
339
340
341 if nam, ok := elim[v]; ok && v.Op == ssaop.OpMove && !used.Has(nam) {
342 if used.Has(n) {
343 continue
344 }
345 s := move[nam]
346 if s == nil {
347 s = ir.NameSet{}
348 move[nam] = s
349 }
350 s.Add(n)
351 continue
352 }
353 changed = usedAdd(n) || changed
354 }
355 }
356 return
357 }
358
359
360 var node *ir.Name
361 for _, a := range args {
362 if n, ok := addr[a]; ok {
363 if node == nil {
364 if !used.Has(n) {
365 node = n
366 }
367 } else {
368 if node == n {
369 continue
370 }
371
372
373
374
375
376 changed = usedAdd(n) || changed
377 }
378 }
379 }
380 if node == nil {
381 return
382 }
383 if addr[v] == nil {
384
385 addr[v] = node
386 changed = true
387 return
388 }
389 if addr[v] != node {
390
391 changed = usedAdd(node) || changed
392 }
393 return
394 }
395
396 iterations := 0
397 for {
398 if iterations == 4 {
399
400 return
401 }
402 iterations++
403 changed := false
404 for _, b := range f.Blocks {
405 for _, v := range b.Values {
406 changed = visit(v) || changed
407 }
408
409 for _, c := range b.ControlValues() {
410 if n, ok := addr[c]; ok {
411 changed = usedAdd(n) || changed
412 }
413 }
414 }
415 if !changed {
416 break
417 }
418 }
419
420
421 for v, n := range elim {
422 if used.Has(n) {
423 continue
424 }
425
426 v.SetArgs1(v.MemoryArg())
427 v.Aux = nil
428 v.AuxInt = 0
429 v.Op = ssaop.OpCopy
430 }
431 }
432
433
434
435 func elimUnreadAutos(f *ssa.Func) {
436
437
438
439 var seen ir.NameSet
440 var stores []*ssa.Value
441 for _, b := range f.Blocks {
442 for _, v := range b.Values {
443 n, ok := v.Aux.(*ir.Name)
444 if !ok {
445 continue
446 }
447 if n.Class != ir.PAUTO && !isABIInternalParam(f, n) {
448 continue
449 }
450
451 effect := v.Op.SymEffect()
452 switch effect {
453 case ssaop.SymNone, ssaop.SymWrite:
454
455
456
457 if !seen.Has(n) {
458 stores = append(stores, v)
459 }
460 default:
461
462
463
464
465
466 if v.Uses > 0 {
467 seen.Add(n)
468 }
469 }
470 }
471 }
472
473
474 for _, store := range stores {
475 n, _ := store.Aux.(*ir.Name)
476 if seen.Has(n) {
477 continue
478 }
479
480
481 store.SetArgs1(store.MemoryArg())
482 store.Aux = nil
483 store.AuxInt = 0
484 store.Op = ssaop.OpCopy
485 }
486 }
487
488
489
490
491
492
493
494
495
496
497 func isABIInternalParam(f *ssa.Func, n *ir.Name) bool {
498 return n.Class == ir.PPARAM && f.ABISelf.Which() == obj.ABIInternal
499 }
500
View as plain text