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