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 clear(f.Names[i:])
236 f.Names = f.Names[:i]
237
238 pendingLines := f.cachedLineStarts
239 pendingLines.clear()
240
241
242 for i, b := range f.Blocks {
243 if !reachable[b.ID] {
244
245 b.ResetControls()
246 }
247 for _, v := range b.Values {
248 if !live[v.ID] {
249 v.resetArgs()
250 if v.Pos.IsStmt() == src.PosIsStmt && reachable[b.ID] {
251 pendingLines.set(v.Pos, int32(i))
252 }
253 }
254 }
255 }
256
257
258 for i := len(order) - 1; i >= 0; i-- {
259 w := order[i]
260 if j := pendingLines.get(w.Pos); j > -1 && f.Blocks[j] == w.Block {
261 w.Pos = w.Pos.WithIsStmt()
262 pendingLines.remove(w.Pos)
263 }
264 }
265
266
267 pendingLines.foreachEntry(func(j int32, l uint, bi int32) {
268 b := f.Blocks[bi]
269 if b.Pos.Line() == l && b.Pos.FileIndex() == j {
270 b.Pos = b.Pos.WithIsStmt()
271 }
272 })
273
274
275
276 for _, b := range f.Blocks {
277 i := 0
278 for _, v := range b.Values {
279 if live[v.ID] {
280 b.Values[i] = v
281 i++
282 } else {
283 f.freeValue(v)
284 }
285 }
286 b.truncateValues(i)
287 }
288
289
290 i = 0
291 for _, b := range f.Blocks {
292 if reachable[b.ID] {
293 f.Blocks[i] = b
294 i++
295 } else {
296 if len(b.Values) > 0 {
297 b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
298 }
299 f.freeBlock(b)
300 }
301 }
302
303 clear(f.Blocks[i:])
304 f.Blocks = f.Blocks[:i]
305 }
306
307
308
309
310
311 func (b *Block) removeEdge(i int) {
312 e := b.Succs[i]
313 c := e.b
314 j := e.i
315
316
317 b.removeSucc(i)
318
319
320 c.removePred(j)
321
322
323 for _, v := range c.Values {
324 if v.Op != OpPhi {
325 continue
326 }
327 c.removePhiArg(v, j)
328
329
330
331
332
333
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
View as plain text