1
2
3
4
5 package ssa
6
7 import (
8 "cmd/internal/src"
9 )
10
11
12
13 func findlive(f *Func) (reachable []bool, live []bool) {
14 reachable = ReachableBlocks(f)
15 var order []*Value
16 live, order = liveValues(f, reachable)
17 f.retDeadcodeLiveOrderStmts(order)
18 return
19 }
20
21
22 func ReachableBlocks(f *Func) []bool {
23 reachable := make([]bool, f.NumBlocks())
24 reachable[f.Entry.ID] = true
25 p := make([]*Block, 0, 64)
26 p = append(p, f.Entry)
27 for len(p) > 0 {
28
29 b := p[len(p)-1]
30 p = p[:len(p)-1]
31
32 s := b.Succs
33 if b.Kind == BlockFirst {
34 s = s[:1]
35 }
36 for _, e := range s {
37 c := e.b
38 if int(c.ID) >= len(reachable) {
39 f.Fatalf("block %s >= f.NumBlocks()=%d?", c, len(reachable))
40 }
41 if !reachable[c.ID] {
42 reachable[c.ID] = true
43 p = append(p, c)
44 }
45 }
46 }
47 return reachable
48 }
49
50
51
52
53
54
55
56 func liveValues(f *Func, reachable []bool) (live []bool, liveOrderStmts []*Value) {
57 live = f.newDeadcodeLive()
58 if cap(live) < f.NumValues() {
59 live = make([]bool, f.NumValues())
60 } else {
61 live = live[:f.NumValues()]
62 for i := range live {
63 live[i] = false
64 }
65 }
66
67 liveOrderStmts = f.newDeadcodeLiveOrderStmts()
68 liveOrderStmts = liveOrderStmts[:0]
69
70
71
72 if f.RegAlloc != nil {
73 for i := range live {
74 live[i] = true
75 }
76 return
77 }
78
79
80 var liveInlIdx map[int]bool
81 pt := f.Config.ctxt.PosTable
82 for _, b := range f.Blocks {
83 for _, v := range b.Values {
84 i := pt.Pos(v.Pos).Base().InliningIndex()
85 if i < 0 {
86 continue
87 }
88 if liveInlIdx == nil {
89 liveInlIdx = map[int]bool{}
90 }
91 liveInlIdx[i] = true
92 }
93 i := pt.Pos(b.Pos).Base().InliningIndex()
94 if i < 0 {
95 continue
96 }
97 if liveInlIdx == nil {
98 liveInlIdx = map[int]bool{}
99 }
100 liveInlIdx[i] = true
101 }
102
103
104 q := f.Cache.deadcode.q[:0]
105 defer func() { f.Cache.deadcode.q = q }()
106
107
108
109 for _, b := range f.Blocks {
110 if !reachable[b.ID] {
111 continue
112 }
113 for _, v := range b.ControlValues() {
114 if !live[v.ID] {
115 live[v.ID] = true
116 q = append(q, v)
117 if v.Pos.IsStmt() != src.PosNotStmt {
118 liveOrderStmts = append(liveOrderStmts, v)
119 }
120 }
121 }
122 for _, v := range b.Values {
123 if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] {
124 live[v.ID] = true
125 q = append(q, v)
126 if v.Pos.IsStmt() != src.PosNotStmt {
127 liveOrderStmts = append(liveOrderStmts, v)
128 }
129 }
130 if v.Type.IsVoid() && !live[v.ID] {
131
132 if v.Op == OpInlMark && !liveInlIdx[int(v.AuxInt)] {
133
134
135
136
137 continue
138 }
139 live[v.ID] = true
140 q = append(q, v)
141 if v.Pos.IsStmt() != src.PosNotStmt {
142 liveOrderStmts = append(liveOrderStmts, v)
143 }
144 }
145 }
146 }
147
148
149 for len(q) > 0 {
150
151 v := q[len(q)-1]
152 q = q[:len(q)-1]
153 for i, x := range v.Args {
154 if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] {
155 continue
156 }
157 if !live[x.ID] {
158 live[x.ID] = true
159 q = append(q, x)
160 if x.Pos.IsStmt() != src.PosNotStmt {
161 liveOrderStmts = append(liveOrderStmts, x)
162 }
163 }
164 }
165 }
166
167 return
168 }
169
170
171 func deadcode(f *Func) {
172
173
174
175
176 if f.RegAlloc != nil {
177 f.Fatalf("deadcode after regalloc")
178 }
179
180
181 reachable := ReachableBlocks(f)
182
183
184 for _, b := range f.Blocks {
185 if reachable[b.ID] {
186 continue
187 }
188 for i := 0; i < len(b.Succs); {
189 e := b.Succs[i]
190 if reachable[e.b.ID] {
191 b.removeEdge(i)
192 } else {
193 i++
194 }
195 }
196 }
197
198
199 for _, b := range f.Blocks {
200 if !reachable[b.ID] {
201 continue
202 }
203 if b.Kind != BlockFirst {
204 continue
205 }
206 b.removeEdge(1)
207 b.Kind = BlockPlain
208 b.Likely = BranchUnknown
209 }
210
211
212 copyelim(f)
213
214
215 live, order := liveValues(f, reachable)
216 defer f.retDeadcodeLive(live)
217 defer f.retDeadcodeLiveOrderStmts(order)
218
219
220 s := f.newSparseSet(f.NumValues())
221 defer f.retSparseSet(s)
222 i := 0
223 for _, name := range f.Names {
224 j := 0
225 s.clear()
226 values := f.NamedValues[*name]
227 for _, v := range values {
228 if live[v.ID] && !s.contains(v.ID) {
229 values[j] = v
230 j++
231 s.add(v.ID)
232 }
233 }
234 if j == 0 {
235 delete(f.NamedValues, *name)
236 } else {
237 f.Names[i] = name
238 i++
239 for k := len(values) - 1; k >= j; k-- {
240 values[k] = nil
241 }
242 f.NamedValues[*name] = values[:j]
243 }
244 }
245 clearNames := f.Names[i:]
246 for j := range clearNames {
247 clearNames[j] = nil
248 }
249 f.Names = f.Names[:i]
250
251 pendingLines := f.cachedLineStarts
252 pendingLines.clear()
253
254
255 for i, b := range f.Blocks {
256 if !reachable[b.ID] {
257
258 b.ResetControls()
259 }
260 for _, v := range b.Values {
261 if !live[v.ID] {
262 v.resetArgs()
263 if v.Pos.IsStmt() == src.PosIsStmt && reachable[b.ID] {
264 pendingLines.set(v.Pos, int32(i))
265 }
266 }
267 }
268 }
269
270
271 for i := len(order) - 1; i >= 0; i-- {
272 w := order[i]
273 if j := pendingLines.get(w.Pos); j > -1 && f.Blocks[j] == w.Block {
274 w.Pos = w.Pos.WithIsStmt()
275 pendingLines.remove(w.Pos)
276 }
277 }
278
279
280 pendingLines.foreachEntry(func(j int32, l uint, bi int32) {
281 b := f.Blocks[bi]
282 if b.Pos.Line() == l && b.Pos.FileIndex() == j {
283 b.Pos = b.Pos.WithIsStmt()
284 }
285 })
286
287
288
289 for _, b := range f.Blocks {
290 i := 0
291 for _, v := range b.Values {
292 if live[v.ID] {
293 b.Values[i] = v
294 i++
295 } else {
296 f.freeValue(v)
297 }
298 }
299 b.truncateValues(i)
300 }
301
302
303 i = 0
304 for _, b := range f.WBLoads {
305 if reachable[b.ID] {
306 f.WBLoads[i] = b
307 i++
308 }
309 }
310 clearWBLoads := f.WBLoads[i:]
311 for j := range clearWBLoads {
312 clearWBLoads[j] = nil
313 }
314 f.WBLoads = f.WBLoads[:i]
315
316
317 i = 0
318 for _, b := range f.Blocks {
319 if reachable[b.ID] {
320 f.Blocks[i] = b
321 i++
322 } else {
323 if len(b.Values) > 0 {
324 b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
325 }
326 f.freeBlock(b)
327 }
328 }
329
330 tail := f.Blocks[i:]
331 for j := range tail {
332 tail[j] = nil
333 }
334 f.Blocks = f.Blocks[:i]
335 }
336
337
338
339 func (b *Block) removeEdge(i int) {
340 e := b.Succs[i]
341 c := e.b
342 j := e.i
343
344
345 b.removeSucc(i)
346
347
348 c.removePred(j)
349
350
351 for _, v := range c.Values {
352 if v.Op != OpPhi {
353 continue
354 }
355 c.removePhiArg(v, j)
356 phielimValue(v)
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388 }
389 }
390
View as plain text