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