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.Cache.freeValueSlice(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.Cache.allocBoolSlice(f.NumValues())
58 liveOrderStmts = f.Cache.allocValueSlice(f.NumValues())[:0]
59
60
61
62 if f.RegAlloc != nil {
63 for i := range live {
64 live[i] = true
65 }
66 return
67 }
68
69
70 var liveInlIdx map[int]bool
71 pt := f.Config.ctxt.PosTable
72 for _, b := range f.Blocks {
73 for _, v := range b.Values {
74 i := pt.Pos(v.Pos).Base().InliningIndex()
75 if i < 0 {
76 continue
77 }
78 if liveInlIdx == nil {
79 liveInlIdx = map[int]bool{}
80 }
81 liveInlIdx[i] = true
82 }
83 i := pt.Pos(b.Pos).Base().InliningIndex()
84 if i < 0 {
85 continue
86 }
87 if liveInlIdx == nil {
88 liveInlIdx = map[int]bool{}
89 }
90 liveInlIdx[i] = true
91 }
92
93
94 q := f.Cache.allocValueSlice(f.NumValues())[:0]
95 defer f.Cache.freeValueSlice(q)
96
97
98
99 for _, b := range f.Blocks {
100 if !reachable[b.ID] {
101 continue
102 }
103 for _, v := range b.ControlValues() {
104 if !live[v.ID] {
105 live[v.ID] = true
106 q = append(q, v)
107 if v.Pos.IsStmt() != src.PosNotStmt {
108 liveOrderStmts = append(liveOrderStmts, v)
109 }
110 }
111 }
112 for _, v := range b.Values {
113 if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects || opcodeTable[v.Op].nilCheck) && !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 if v.Op == OpInlMark {
121 if !liveInlIdx[int(v.AuxInt)] {
122
123
124
125
126 continue
127 }
128 live[v.ID] = true
129 q = append(q, v)
130 if v.Pos.IsStmt() != src.PosNotStmt {
131 liveOrderStmts = append(liveOrderStmts, v)
132 }
133 }
134 }
135 }
136
137
138 for len(q) > 0 {
139
140 v := q[len(q)-1]
141 q[len(q)-1] = nil
142 q = q[:len(q)-1]
143 for i, x := range v.Args {
144 if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] {
145 continue
146 }
147 if !live[x.ID] {
148 live[x.ID] = true
149 q = append(q, x)
150 if x.Pos.IsStmt() != src.PosNotStmt {
151 liveOrderStmts = append(liveOrderStmts, x)
152 }
153 }
154 }
155 }
156
157 return
158 }
159
160
161 func deadcode(f *Func) {
162
163
164
165
166 if f.RegAlloc != nil {
167 f.Fatalf("deadcode after regalloc")
168 }
169
170
171 reachable := ReachableBlocks(f)
172
173
174 for _, b := range f.Blocks {
175 if reachable[b.ID] {
176 continue
177 }
178 for i := 0; i < len(b.Succs); {
179 e := b.Succs[i]
180 if reachable[e.b.ID] {
181 b.removeEdge(i)
182 } else {
183 i++
184 }
185 }
186 }
187
188
189 for _, b := range f.Blocks {
190 if !reachable[b.ID] {
191 continue
192 }
193 if b.Kind != BlockFirst {
194 continue
195 }
196 b.removeEdge(1)
197 b.Kind = BlockPlain
198 b.Likely = BranchUnknown
199 }
200
201
202 copyelim(f)
203
204
205 live, order := liveValues(f, reachable)
206 defer func() { f.Cache.freeBoolSlice(live) }()
207 defer func() { f.Cache.freeValueSlice(order) }()
208
209
210 s := f.newSparseSet(f.NumValues())
211 defer f.retSparseSet(s)
212 i := 0
213 for _, name := range f.Names {
214 j := 0
215 s.clear()
216 values := f.NamedValues[*name]
217 for _, v := range values {
218 if live[v.ID] && !s.contains(v.ID) {
219 values[j] = v
220 j++
221 s.add(v.ID)
222 }
223 }
224 if j == 0 {
225 delete(f.NamedValues, *name)
226 } else {
227 f.Names[i] = name
228 i++
229 for k := len(values) - 1; k >= j; k-- {
230 values[k] = nil
231 }
232 f.NamedValues[*name] = values[:j]
233 }
234 }
235 clearNames := f.Names[i:]
236 for j := range clearNames {
237 clearNames[j] = nil
238 }
239 f.Names = f.Names[:i]
240
241 pendingLines := f.cachedLineStarts
242 pendingLines.clear()
243
244
245 for i, b := range f.Blocks {
246 if !reachable[b.ID] {
247
248 b.ResetControls()
249 }
250 for _, v := range b.Values {
251 if !live[v.ID] {
252 v.resetArgs()
253 if v.Pos.IsStmt() == src.PosIsStmt && reachable[b.ID] {
254 pendingLines.set(v.Pos, int32(i))
255 }
256 }
257 }
258 }
259
260
261 for i := len(order) - 1; i >= 0; i-- {
262 w := order[i]
263 if j := pendingLines.get(w.Pos); j > -1 && f.Blocks[j] == w.Block {
264 w.Pos = w.Pos.WithIsStmt()
265 pendingLines.remove(w.Pos)
266 }
267 }
268
269
270 pendingLines.foreachEntry(func(j int32, l uint, bi int32) {
271 b := f.Blocks[bi]
272 if b.Pos.Line() == l && b.Pos.FileIndex() == j {
273 b.Pos = b.Pos.WithIsStmt()
274 }
275 })
276
277
278
279 for _, b := range f.Blocks {
280 i := 0
281 for _, v := range b.Values {
282 if live[v.ID] {
283 b.Values[i] = v
284 i++
285 } else {
286 f.freeValue(v)
287 }
288 }
289 b.truncateValues(i)
290 }
291
292
293 i = 0
294 for _, b := range f.Blocks {
295 if reachable[b.ID] {
296 f.Blocks[i] = b
297 i++
298 } else {
299 if len(b.Values) > 0 {
300 b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
301 }
302 f.freeBlock(b)
303 }
304 }
305
306 tail := f.Blocks[i:]
307 for j := range tail {
308 tail[j] = nil
309 }
310 f.Blocks = f.Blocks[:i]
311 }
312
313
314
315
316
317 func (b *Block) removeEdge(i int) {
318 e := b.Succs[i]
319 c := e.b
320 j := e.i
321
322
323 b.removeSucc(i)
324
325
326 c.removePred(j)
327
328
329 for _, v := range c.Values {
330 if v.Op != OpPhi {
331 continue
332 }
333 c.removePhiArg(v, j)
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 }
366 }
367
View as plain text