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