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