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