github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/ssa/deadstore.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  // dse does dead-store elimination on the Function.
     8  // Dead stores are those which are unconditionally followed by
     9  // another store to the same location, with no intervening load.
    10  // This implementation only works within a basic block. TODO: use something more global.
    11  func dse(f *Func) {
    12  	var stores []*Value
    13  	loadUse := f.newSparseSet(f.NumValues())
    14  	defer f.retSparseSet(loadUse)
    15  	storeUse := f.newSparseSet(f.NumValues())
    16  	defer f.retSparseSet(storeUse)
    17  	shadowed := f.newSparseSet(f.NumValues())
    18  	defer f.retSparseSet(shadowed)
    19  	for _, b := range f.Blocks {
    20  		// Find all the stores in this block. Categorize their uses:
    21  		//  loadUse contains stores which are used by a subsequent load.
    22  		//  storeUse contains stores which are used by a subsequent store.
    23  		loadUse.clear()
    24  		storeUse.clear()
    25  		stores = stores[:0]
    26  		for _, v := range b.Values {
    27  			if v.Op == OpPhi {
    28  				// Ignore phis - they will always be first and can't be eliminated
    29  				continue
    30  			}
    31  			if v.Type.IsMemory() {
    32  				stores = append(stores, v)
    33  				for _, a := range v.Args {
    34  					if a.Block == b && a.Type.IsMemory() {
    35  						storeUse.add(a.ID)
    36  						if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef && v.Op != OpVarKill {
    37  							// CALL, DUFFCOPY, etc. are both
    38  							// reads and writes.
    39  							loadUse.add(a.ID)
    40  						}
    41  					}
    42  				}
    43  			} else {
    44  				for _, a := range v.Args {
    45  					if a.Block == b && a.Type.IsMemory() {
    46  						loadUse.add(a.ID)
    47  					}
    48  				}
    49  			}
    50  		}
    51  		if len(stores) == 0 {
    52  			continue
    53  		}
    54  
    55  		// find last store in the block
    56  		var last *Value
    57  		for _, v := range stores {
    58  			if storeUse.contains(v.ID) {
    59  				continue
    60  			}
    61  			if last != nil {
    62  				b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
    63  			}
    64  			last = v
    65  		}
    66  		if last == nil {
    67  			b.Fatalf("no last store found - cycle?")
    68  		}
    69  
    70  		// Walk backwards looking for dead stores. Keep track of shadowed addresses.
    71  		// An "address" is an SSA Value which encodes both the address and size of
    72  		// the write. This code will not remove dead stores to the same address
    73  		// of different types.
    74  		shadowed.clear()
    75  		v := last
    76  
    77  	walkloop:
    78  		if loadUse.contains(v.ID) {
    79  			// Someone might be reading this memory state.
    80  			// Clear all shadowed addresses.
    81  			shadowed.clear()
    82  		}
    83  		if v.Op == OpStore || v.Op == OpZero {
    84  			if shadowed.contains(v.Args[0].ID) {
    85  				// Modify store into a copy
    86  				if v.Op == OpStore {
    87  					// store addr value mem
    88  					v.SetArgs1(v.Args[2])
    89  				} else {
    90  					// zero addr mem
    91  					sz := v.Args[0].Type.ElemType().Size()
    92  					if v.AuxInt != sz {
    93  						f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
    94  							v.AuxInt, sz, v.LongString())
    95  					}
    96  					v.SetArgs1(v.Args[1])
    97  				}
    98  				v.Aux = nil
    99  				v.AuxInt = 0
   100  				v.Op = OpCopy
   101  			} else {
   102  				shadowed.add(v.Args[0].ID)
   103  			}
   104  		}
   105  		// walk to previous store
   106  		if v.Op == OpPhi {
   107  			continue // At start of block.  Move on to next block.
   108  		}
   109  		for _, a := range v.Args {
   110  			if a.Block == b && a.Type.IsMemory() {
   111  				v = a
   112  				goto walkloop
   113  			}
   114  		}
   115  	}
   116  }