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