github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/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  import (
     8  	"cmd/compile/internal/types"
     9  	"cmd/internal/src"
    10  )
    11  
    12  // dse does dead-store elimination on the Function.
    13  // Dead stores are those which are unconditionally followed by
    14  // another store to the same location, with no intervening load.
    15  // This implementation only works within a basic block. TODO: use something more global.
    16  func dse(f *Func) {
    17  	var stores []*Value
    18  	loadUse := f.newSparseSet(f.NumValues())
    19  	defer f.retSparseSet(loadUse)
    20  	storeUse := f.newSparseSet(f.NumValues())
    21  	defer f.retSparseSet(storeUse)
    22  	shadowed := newSparseMap(f.NumValues()) // TODO: cache
    23  	for _, b := range f.Blocks {
    24  		// Find all the stores in this block. Categorize their uses:
    25  		//  loadUse contains stores which are used by a subsequent load.
    26  		//  storeUse contains stores which are used by a subsequent store.
    27  		loadUse.clear()
    28  		storeUse.clear()
    29  		stores = stores[:0]
    30  		for _, v := range b.Values {
    31  			if v.Op == OpPhi {
    32  				// Ignore phis - they will always be first and can't be eliminated
    33  				continue
    34  			}
    35  			if v.Type.IsMemory() {
    36  				stores = append(stores, v)
    37  				for _, a := range v.Args {
    38  					if a.Block == b && a.Type.IsMemory() {
    39  						storeUse.add(a.ID)
    40  						if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef && v.Op != OpVarKill {
    41  							// CALL, DUFFCOPY, etc. are both
    42  							// reads and writes.
    43  							loadUse.add(a.ID)
    44  						}
    45  					}
    46  				}
    47  			} else {
    48  				for _, a := range v.Args {
    49  					if a.Block == b && a.Type.IsMemory() {
    50  						loadUse.add(a.ID)
    51  					}
    52  				}
    53  			}
    54  		}
    55  		if len(stores) == 0 {
    56  			continue
    57  		}
    58  
    59  		// find last store in the block
    60  		var last *Value
    61  		for _, v := range stores {
    62  			if storeUse.contains(v.ID) {
    63  				continue
    64  			}
    65  			if last != nil {
    66  				b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
    67  			}
    68  			last = v
    69  		}
    70  		if last == nil {
    71  			b.Fatalf("no last store found - cycle?")
    72  		}
    73  
    74  		// Walk backwards looking for dead stores. Keep track of shadowed addresses.
    75  		// An "address" is an SSA Value which encodes both the address and size of
    76  		// the write. This code will not remove dead stores to the same address
    77  		// of different types.
    78  		shadowed.clear()
    79  		v := last
    80  
    81  	walkloop:
    82  		if loadUse.contains(v.ID) {
    83  			// Someone might be reading this memory state.
    84  			// Clear all shadowed addresses.
    85  			shadowed.clear()
    86  		}
    87  		if v.Op == OpStore || v.Op == OpZero {
    88  			var sz int64
    89  			if v.Op == OpStore {
    90  				sz = v.Aux.(*types.Type).Size()
    91  			} else { // OpZero
    92  				sz = v.AuxInt
    93  			}
    94  			if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
    95  				// Modify store into a copy
    96  				if v.Op == OpStore {
    97  					// store addr value mem
    98  					v.SetArgs1(v.Args[2])
    99  				} else {
   100  					// zero addr mem
   101  					typesz := v.Args[0].Type.ElemType().Size()
   102  					if sz != typesz {
   103  						f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
   104  							sz, typesz, v.LongString())
   105  					}
   106  					v.SetArgs1(v.Args[1])
   107  				}
   108  				v.Aux = nil
   109  				v.AuxInt = 0
   110  				v.Op = OpCopy
   111  			} else {
   112  				if sz > 0x7fffffff { // work around sparseMap's int32 value type
   113  					sz = 0x7fffffff
   114  				}
   115  				shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
   116  			}
   117  		}
   118  		// walk to previous store
   119  		if v.Op == OpPhi {
   120  			// At start of block.  Move on to next block.
   121  			// The memory phi, if it exists, is always
   122  			// the first logical store in the block.
   123  			// (Even if it isn't the first in the current b.Values order.)
   124  			continue
   125  		}
   126  		for _, a := range v.Args {
   127  			if a.Block == b && a.Type.IsMemory() {
   128  				v = a
   129  				goto walkloop
   130  			}
   131  		}
   132  	}
   133  }
   134  
   135  // elimUnreadAutos deletes stores (and associated bookkeeping ops VarDef and VarKill)
   136  // to autos that are never read from.
   137  func elimUnreadAutos(f *Func) {
   138  	// Loop over all ops that affect autos taking note of which
   139  	// autos we need and also stores that we might be able to
   140  	// eliminate.
   141  	seen := make(map[GCNode]bool)
   142  	var stores []*Value
   143  	for _, b := range f.Blocks {
   144  		for _, v := range b.Values {
   145  			n, ok := v.Aux.(GCNode)
   146  			if !ok {
   147  				continue
   148  			}
   149  			if n.StorageClass() != ClassAuto {
   150  				continue
   151  			}
   152  
   153  			effect := v.Op.SymEffect()
   154  			switch effect {
   155  			case SymNone, SymWrite:
   156  				// If we haven't seen the auto yet
   157  				// then this might be a store we can
   158  				// eliminate.
   159  				if !seen[n] {
   160  					stores = append(stores, v)
   161  				}
   162  			default:
   163  				// Assume the auto is needed (loaded,
   164  				// has its address taken, etc.).
   165  				// Note we have to check the uses
   166  				// because dead loads haven't been
   167  				// eliminated yet.
   168  				if v.Uses > 0 {
   169  					seen[n] = true
   170  				}
   171  			}
   172  		}
   173  	}
   174  
   175  	// Eliminate stores to unread autos.
   176  	for _, store := range stores {
   177  		n, _ := store.Aux.(GCNode)
   178  		if seen[n] {
   179  			continue
   180  		}
   181  
   182  		// replace store with OpCopy
   183  		store.SetArgs1(store.MemoryArg())
   184  		store.Aux = nil
   185  		store.AuxInt = 0
   186  		store.Op = OpCopy
   187  	}
   188  }