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