github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/ssa/deadcode.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 // findlive returns the reachable blocks and live values in f. 8 func findlive(f *Func) (reachable []bool, live []bool) { 9 reachable = reachableBlocks(f) 10 live = liveValues(f, reachable) 11 return 12 } 13 14 // reachableBlocks returns the reachable blocks in f. 15 func reachableBlocks(f *Func) []bool { 16 reachable := make([]bool, f.NumBlocks()) 17 reachable[f.Entry.ID] = true 18 p := []*Block{f.Entry} // stack-like worklist 19 for len(p) > 0 { 20 // Pop a reachable block 21 b := p[len(p)-1] 22 p = p[:len(p)-1] 23 // Mark successors as reachable 24 s := b.Succs 25 if b.Kind == BlockFirst { 26 s = s[:1] 27 } 28 for _, e := range s { 29 c := e.b 30 if !reachable[c.ID] { 31 reachable[c.ID] = true 32 p = append(p, c) // push 33 } 34 } 35 } 36 return reachable 37 } 38 39 // liveValues returns the live values in f. 40 // reachable is a map from block ID to whether the block is reachable. 41 func liveValues(f *Func, reachable []bool) []bool { 42 live := make([]bool, f.NumValues()) 43 44 // After regalloc, consider all values to be live. 45 // See the comment at the top of regalloc.go and in deadcode for details. 46 if f.RegAlloc != nil { 47 for i := range live { 48 live[i] = true 49 } 50 return live 51 } 52 53 // Find all live values 54 var q []*Value // stack-like worklist of unscanned values 55 56 // Starting set: all control values of reachable blocks are live. 57 for _, b := range f.Blocks { 58 if !reachable[b.ID] { 59 continue 60 } 61 if v := b.Control; v != nil && !live[v.ID] { 62 live[v.ID] = true 63 q = append(q, v) 64 } 65 } 66 67 // Compute transitive closure of live values. 68 for len(q) > 0 { 69 // pop a reachable value 70 v := q[len(q)-1] 71 q = q[:len(q)-1] 72 for i, x := range v.Args { 73 if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] { 74 continue 75 } 76 if !live[x.ID] { 77 live[x.ID] = true 78 q = append(q, x) // push 79 } 80 } 81 } 82 83 return live 84 } 85 86 // deadcode removes dead code from f. 87 func deadcode(f *Func) { 88 // deadcode after regalloc is forbidden for now. Regalloc 89 // doesn't quite generate legal SSA which will lead to some 90 // required moves being eliminated. See the comment at the 91 // top of regalloc.go for details. 92 if f.RegAlloc != nil { 93 f.Fatalf("deadcode after regalloc") 94 } 95 96 // Find reachable blocks. 97 reachable := reachableBlocks(f) 98 99 // Get rid of edges from dead to live code. 100 for _, b := range f.Blocks { 101 if reachable[b.ID] { 102 continue 103 } 104 for i := 0; i < len(b.Succs); { 105 e := b.Succs[i] 106 if reachable[e.b.ID] { 107 b.removeEdge(i) 108 } else { 109 i++ 110 } 111 } 112 } 113 114 // Get rid of dead edges from live code. 115 for _, b := range f.Blocks { 116 if !reachable[b.ID] { 117 continue 118 } 119 if b.Kind != BlockFirst { 120 continue 121 } 122 b.removeEdge(1) 123 b.Kind = BlockPlain 124 b.Likely = BranchUnknown 125 } 126 127 // Splice out any copies introduced during dead block removal. 128 copyelim(f) 129 130 // Find live values. 131 live := liveValues(f, reachable) 132 133 // Remove dead & duplicate entries from namedValues map. 134 s := f.newSparseSet(f.NumValues()) 135 defer f.retSparseSet(s) 136 i := 0 137 for _, name := range f.Names { 138 j := 0 139 s.clear() 140 values := f.NamedValues[name] 141 for _, v := range values { 142 if live[v.ID] && !s.contains(v.ID) { 143 values[j] = v 144 j++ 145 s.add(v.ID) 146 } 147 } 148 if j == 0 { 149 delete(f.NamedValues, name) 150 } else { 151 f.Names[i] = name 152 i++ 153 for k := len(values) - 1; k >= j; k-- { 154 values[k] = nil 155 } 156 f.NamedValues[name] = values[:j] 157 } 158 } 159 for k := len(f.Names) - 1; k >= i; k-- { 160 f.Names[k] = LocalSlot{} 161 } 162 f.Names = f.Names[:i] 163 164 // Unlink values. 165 for _, b := range f.Blocks { 166 if !reachable[b.ID] { 167 b.SetControl(nil) 168 } 169 for _, v := range b.Values { 170 if !live[v.ID] { 171 v.resetArgs() 172 } 173 } 174 } 175 176 // Remove dead values from blocks' value list. Return dead 177 // values to the allocator. 178 for _, b := range f.Blocks { 179 i := 0 180 for _, v := range b.Values { 181 if live[v.ID] { 182 b.Values[i] = v 183 i++ 184 } else { 185 f.freeValue(v) 186 } 187 } 188 // aid GC 189 tail := b.Values[i:] 190 for j := range tail { 191 tail[j] = nil 192 } 193 b.Values = b.Values[:i] 194 } 195 196 // Remove unreachable blocks. Return dead blocks to allocator. 197 i = 0 198 for _, b := range f.Blocks { 199 if reachable[b.ID] { 200 f.Blocks[i] = b 201 i++ 202 } else { 203 if len(b.Values) > 0 { 204 b.Fatalf("live values in unreachable block %v: %v", b, b.Values) 205 } 206 f.freeBlock(b) 207 } 208 } 209 // zero remainder to help GC 210 tail := f.Blocks[i:] 211 for j := range tail { 212 tail[j] = nil 213 } 214 f.Blocks = f.Blocks[:i] 215 } 216 217 // removeEdge removes the i'th outgoing edge from b (and 218 // the corresponding incoming edge from b.Succs[i].b). 219 func (b *Block) removeEdge(i int) { 220 e := b.Succs[i] 221 c := e.b 222 j := e.i 223 224 // Adjust b.Succs 225 b.removeSucc(i) 226 227 // Adjust c.Preds 228 c.removePred(j) 229 230 // Remove phi args from c's phis. 231 n := len(c.Preds) 232 for _, v := range c.Values { 233 if v.Op != OpPhi { 234 continue 235 } 236 v.Args[j].Uses-- 237 v.Args[j] = v.Args[n] 238 v.Args[n] = nil 239 v.Args = v.Args[:n] 240 phielimValue(v) 241 // Note: this is trickier than it looks. Replacing 242 // a Phi with a Copy can in general cause problems because 243 // Phi and Copy don't have exactly the same semantics. 244 // Phi arguments always come from a predecessor block, 245 // whereas copies don't. This matters in loops like: 246 // 1: x = (Phi y) 247 // y = (Add x 1) 248 // goto 1 249 // If we replace Phi->Copy, we get 250 // 1: x = (Copy y) 251 // y = (Add x 1) 252 // goto 1 253 // (Phi y) refers to the *previous* value of y, whereas 254 // (Copy y) refers to the *current* value of y. 255 // The modified code has a cycle and the scheduler 256 // will barf on it. 257 // 258 // Fortunately, this situation can only happen for dead 259 // code loops. We know the code we're working with is 260 // not dead, so we're ok. 261 // Proof: If we have a potential bad cycle, we have a 262 // situation like this: 263 // x = (Phi z) 264 // y = (op1 x ...) 265 // z = (op2 y ...) 266 // Where opX are not Phi ops. But such a situation 267 // implies a cycle in the dominator graph. In the 268 // example, x.Block dominates y.Block, y.Block dominates 269 // z.Block, and z.Block dominates x.Block (treating 270 // "dominates" as reflexive). Cycles in the dominator 271 // graph can only happen in an unreachable cycle. 272 } 273 }