Source file src/pkg/cmd/compile/internal/ssa/deadcode.go
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 if v := b.Control; v != nil && !live[v.ID] {
114 live[v.ID] = true
115 q = append(q, v)
116 if v.Pos.IsStmt() != src.PosNotStmt {
117 liveOrderStmts = append(liveOrderStmts, v)
118 }
119 }
120 for _, v := range b.Values {
121 if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] {
122 live[v.ID] = true
123 q = append(q, v)
124 if v.Pos.IsStmt() != src.PosNotStmt {
125 liveOrderStmts = append(liveOrderStmts, v)
126 }
127 }
128 if v.Type.IsVoid() && !live[v.ID] {
129
130 if v.Op == OpInlMark && !liveInlIdx[int(v.AuxInt)] {
131
132
133
134
135 continue
136 }
137 live[v.ID] = true
138 q = append(q, v)
139 if v.Pos.IsStmt() != src.PosNotStmt {
140 liveOrderStmts = append(liveOrderStmts, v)
141 }
142 }
143 }
144 }
145
146
147 for len(q) > 0 {
148
149 v := q[len(q)-1]
150 q = q[:len(q)-1]
151 for i, x := range v.Args {
152 if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] {
153 continue
154 }
155 if !live[x.ID] {
156 live[x.ID] = true
157 q = append(q, x)
158 if x.Pos.IsStmt() != src.PosNotStmt {
159 liveOrderStmts = append(liveOrderStmts, x)
160 }
161 }
162 }
163 }
164
165 return
166 }
167
168
169 func deadcode(f *Func) {
170
171
172
173
174 if f.RegAlloc != nil {
175 f.Fatalf("deadcode after regalloc")
176 }
177
178
179 reachable := ReachableBlocks(f)
180
181
182 for _, b := range f.Blocks {
183 if reachable[b.ID] {
184 continue
185 }
186 for i := 0; i < len(b.Succs); {
187 e := b.Succs[i]
188 if reachable[e.b.ID] {
189 b.removeEdge(i)
190 } else {
191 i++
192 }
193 }
194 }
195
196
197 for _, b := range f.Blocks {
198 if !reachable[b.ID] {
199 continue
200 }
201 if b.Kind != BlockFirst {
202 continue
203 }
204 b.removeEdge(1)
205 b.Kind = BlockPlain
206 b.Likely = BranchUnknown
207 }
208
209
210 copyelim(f)
211
212
213 live, order := liveValues(f, reachable)
214 defer f.retDeadcodeLive(live)
215 defer f.retDeadcodeLiveOrderStmts(order)
216
217
218 s := f.newSparseSet(f.NumValues())
219 defer f.retSparseSet(s)
220 i := 0
221 for _, name := range f.Names {
222 j := 0
223 s.clear()
224 values := f.NamedValues[name]
225 for _, v := range values {
226 if live[v.ID] && !s.contains(v.ID) {
227 values[j] = v
228 j++
229 s.add(v.ID)
230 }
231 }
232 if j == 0 {
233 delete(f.NamedValues, name)
234 } else {
235 f.Names[i] = name
236 i++
237 for k := len(values) - 1; k >= j; k-- {
238 values[k] = nil
239 }
240 f.NamedValues[name] = values[:j]
241 }
242 }
243 for k := len(f.Names) - 1; k >= i; k-- {
244 f.Names[k] = LocalSlot{}
245 }
246 f.Names = f.Names[:i]
247
248 pendingLines := f.cachedLineStarts
249 pendingLines.clear()
250
251
252 for i, b := range f.Blocks {
253 if !reachable[b.ID] {
254
255 b.SetControl(nil)
256 }
257 for _, v := range b.Values {
258 if !live[v.ID] {
259 v.resetArgs()
260 if v.Pos.IsStmt() == src.PosIsStmt && reachable[b.ID] {
261 pendingLines.set(v.Pos, int32(i))
262 }
263 }
264 }
265 }
266
267
268 for i := len(order) - 1; i >= 0; i-- {
269 w := order[i]
270 if j := pendingLines.get(w.Pos); j > -1 && f.Blocks[j] == w.Block {
271 w.Pos = w.Pos.WithIsStmt()
272 pendingLines.remove(w.Pos)
273 }
274 }
275
276
277 pendingLines.foreachEntry(func(j int32, l uint, bi int32) {
278 b := f.Blocks[bi]
279 if b.Pos.Line() == l && b.Pos.FileIndex() == j {
280 b.Pos = b.Pos.WithIsStmt()
281 }
282 })
283
284
285
286 for _, b := range f.Blocks {
287 i := 0
288 for _, v := range b.Values {
289 if live[v.ID] {
290 b.Values[i] = v
291 i++
292 } else {
293 f.freeValue(v)
294 }
295 }
296
297 tail := b.Values[i:]
298 for j := range tail {
299 tail[j] = nil
300 }
301 b.Values = b.Values[:i]
302 }
303
304
305 i = 0
306 for _, b := range f.WBLoads {
307 if reachable[b.ID] {
308 f.WBLoads[i] = b
309 i++
310 }
311 }
312 for j := i; j < len(f.WBLoads); j++ {
313 f.WBLoads[j] = nil
314 }
315 f.WBLoads = f.WBLoads[:i]
316
317
318 i = 0
319 for _, b := range f.Blocks {
320 if reachable[b.ID] {
321 f.Blocks[i] = b
322 i++
323 } else {
324 if len(b.Values) > 0 {
325 b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
326 }
327 f.freeBlock(b)
328 }
329 }
330
331 tail := f.Blocks[i:]
332 for j := range tail {
333 tail[j] = nil
334 }
335 f.Blocks = f.Blocks[:i]
336 }
337
338
339
340 func (b *Block) removeEdge(i int) {
341 e := b.Succs[i]
342 c := e.b
343 j := e.i
344
345
346 b.removeSucc(i)
347
348
349 c.removePred(j)
350
351
352 n := len(c.Preds)
353 for _, v := range c.Values {
354 if v.Op != OpPhi {
355 continue
356 }
357 v.Args[j].Uses--
358 v.Args[j] = v.Args[n]
359 v.Args[n] = nil
360 v.Args = v.Args[:n]
361 phielimValue(v)
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
391
392
393 }
394 }
395
View as plain text