1  
     2  
     3  
     4  
     5  package ssa
     6  
     7  import (
     8  	"cmd/compile/internal/ir"
     9  	"cmd/compile/internal/types"
    10  )
    11  
    12  
    13  
    14  
    15  
    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 := f.newSparseMap(f.NumValues())
    23  	defer f.retSparseMap(shadowed)
    24  	
    25  	localAddrs := map[any]*Value{}
    26  	for _, b := range f.Blocks {
    27  		
    28  		
    29  		
    30  		loadUse.clear()
    31  		storeUse.clear()
    32  		clear(localAddrs)
    33  		stores = stores[:0]
    34  		for _, v := range b.Values {
    35  			if v.Op == OpPhi {
    36  				
    37  				continue
    38  			}
    39  			if v.Type.IsMemory() {
    40  				stores = append(stores, v)
    41  				for _, a := range v.Args {
    42  					if a.Block == b && a.Type.IsMemory() {
    43  						storeUse.add(a.ID)
    44  						if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef {
    45  							
    46  							
    47  							loadUse.add(a.ID)
    48  						}
    49  					}
    50  				}
    51  			} else {
    52  				if v.Op == OpLocalAddr {
    53  					if _, ok := localAddrs[v.Aux]; !ok {
    54  						localAddrs[v.Aux] = v
    55  					}
    56  					continue
    57  				}
    58  				if v.Op == OpInlMark || v.Op == OpConvert {
    59  					
    60  					continue
    61  				}
    62  				for _, a := range v.Args {
    63  					if a.Block == b && a.Type.IsMemory() {
    64  						loadUse.add(a.ID)
    65  					}
    66  				}
    67  			}
    68  		}
    69  		if len(stores) == 0 {
    70  			continue
    71  		}
    72  
    73  		
    74  		var last *Value
    75  		for _, v := range stores {
    76  			if storeUse.contains(v.ID) {
    77  				continue
    78  			}
    79  			if last != nil {
    80  				b.Fatalf("two final stores - simultaneous live stores %s %s", last.LongString(), v.LongString())
    81  			}
    82  			last = v
    83  		}
    84  		if last == nil {
    85  			b.Fatalf("no last store found - cycle?")
    86  		}
    87  
    88  		
    89  		
    90  		
    91  		
    92  		
    93  		
    94  		shadowed.clear()
    95  		v := last
    96  
    97  	walkloop:
    98  		if loadUse.contains(v.ID) {
    99  			
   100  			
   101  			shadowed.clear()
   102  		}
   103  		if v.Op == OpStore || v.Op == OpZero {
   104  			ptr := v.Args[0]
   105  			var off int64
   106  			for ptr.Op == OpOffPtr { 
   107  				off += ptr.AuxInt
   108  				ptr = ptr.Args[0]
   109  			}
   110  			var sz int64
   111  			if v.Op == OpStore {
   112  				sz = v.Aux.(*types.Type).Size()
   113  			} else { 
   114  				sz = v.AuxInt
   115  			}
   116  			if ptr.Op == OpLocalAddr {
   117  				if la, ok := localAddrs[ptr.Aux]; ok {
   118  					ptr = la
   119  				}
   120  			}
   121  			sr := shadowRange(shadowed.get(ptr.ID))
   122  			if sr.contains(off, off+sz) {
   123  				
   124  				
   125  				if v.Op == OpStore {
   126  					
   127  					v.SetArgs1(v.Args[2])
   128  				} else {
   129  					
   130  					v.SetArgs1(v.Args[1])
   131  				}
   132  				v.Aux = nil
   133  				v.AuxInt = 0
   134  				v.Op = OpCopy
   135  			} else {
   136  				
   137  				shadowed.set(ptr.ID, int32(sr.merge(off, off+sz)))
   138  			}
   139  		}
   140  		
   141  		if v.Op == OpPhi {
   142  			
   143  			
   144  			
   145  			
   146  			continue
   147  		}
   148  		for _, a := range v.Args {
   149  			if a.Block == b && a.Type.IsMemory() {
   150  				v = a
   151  				goto walkloop
   152  			}
   153  		}
   154  	}
   155  }
   156  
   157  
   158  
   159  
   160  
   161  
   162  type shadowRange int32
   163  
   164  func (sr shadowRange) lo() int64 {
   165  	return int64(sr & 0xffff)
   166  }
   167  
   168  func (sr shadowRange) hi() int64 {
   169  	return int64((sr >> 16) & 0xffff)
   170  }
   171  
   172  
   173  func (sr shadowRange) contains(lo, hi int64) bool {
   174  	return lo >= sr.lo() && hi <= sr.hi()
   175  }
   176  
   177  
   178  
   179  func (sr shadowRange) merge(lo, hi int64) shadowRange {
   180  	if lo < 0 || hi > 0xffff {
   181  		
   182  		return sr
   183  	}
   184  	if sr.lo() == sr.hi() {
   185  		
   186  		return shadowRange(lo + hi<<16)
   187  	}
   188  	if hi < sr.lo() || lo > sr.hi() {
   189  		
   190  		
   191  		
   192  		if sr.hi()-sr.lo() >= hi-lo {
   193  			return sr
   194  		}
   195  		return shadowRange(lo + hi<<16)
   196  	}
   197  	
   198  	return shadowRange(min(lo, sr.lo()) + max(hi, sr.hi())<<16)
   199  }
   200  
   201  
   202  
   203  
   204  
   205  func elimDeadAutosGeneric(f *Func) {
   206  	addr := make(map[*Value]*ir.Name) 
   207  	elim := make(map[*Value]*ir.Name) 
   208  	var used ir.NameSet               
   209  
   210  	
   211  	visit := func(v *Value) (changed bool) {
   212  		args := v.Args
   213  		switch v.Op {
   214  		case OpAddr, OpLocalAddr:
   215  			
   216  			n, ok := v.Aux.(*ir.Name)
   217  			if !ok || n.Class != ir.PAUTO {
   218  				return
   219  			}
   220  			if addr[v] == nil {
   221  				addr[v] = n
   222  				changed = true
   223  			}
   224  			return
   225  		case OpVarDef:
   226  			
   227  			n, ok := v.Aux.(*ir.Name)
   228  			if !ok || n.Class != ir.PAUTO {
   229  				return
   230  			}
   231  			if elim[v] == nil {
   232  				elim[v] = n
   233  				changed = true
   234  			}
   235  			return
   236  		case OpVarLive:
   237  			
   238  
   239  			
   240  			
   241  			
   242  			
   243  			n, ok := v.Aux.(*ir.Name)
   244  			if !ok || n.Class != ir.PAUTO {
   245  				return
   246  			}
   247  			if !used.Has(n) {
   248  				used.Add(n)
   249  				changed = true
   250  			}
   251  			return
   252  		case OpStore, OpMove, OpZero:
   253  			
   254  			n, ok := addr[args[0]]
   255  			if ok && elim[v] == nil {
   256  				elim[v] = n
   257  				changed = true
   258  			}
   259  			
   260  			args = args[1:]
   261  		}
   262  
   263  		
   264  		
   265  		
   266  		if v.Op.SymEffect() != SymNone && v.Op != OpArg {
   267  			panic("unhandled op with sym effect")
   268  		}
   269  
   270  		if v.Uses == 0 && v.Op != OpNilCheck && !v.Op.IsCall() && !v.Op.HasSideEffects() || len(args) == 0 {
   271  			
   272  			
   273  			return
   274  		}
   275  
   276  		
   277  		
   278  		
   279  		if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == OpPhi || v.MemoryArg() != nil {
   280  			for _, a := range args {
   281  				if n, ok := addr[a]; ok {
   282  					if !used.Has(n) {
   283  						used.Add(n)
   284  						changed = true
   285  					}
   286  				}
   287  			}
   288  			return
   289  		}
   290  
   291  		
   292  		var node *ir.Name
   293  		for _, a := range args {
   294  			if n, ok := addr[a]; ok && !used.Has(n) {
   295  				if node == nil {
   296  					node = n
   297  				} else if node != n {
   298  					
   299  					
   300  					
   301  					
   302  					
   303  					used.Add(n)
   304  					changed = true
   305  				}
   306  			}
   307  		}
   308  		if node == nil {
   309  			return
   310  		}
   311  		if addr[v] == nil {
   312  			
   313  			addr[v] = node
   314  			changed = true
   315  			return
   316  		}
   317  		if addr[v] != node {
   318  			
   319  			used.Add(node)
   320  			changed = true
   321  		}
   322  		return
   323  	}
   324  
   325  	iterations := 0
   326  	for {
   327  		if iterations == 4 {
   328  			
   329  			return
   330  		}
   331  		iterations++
   332  		changed := false
   333  		for _, b := range f.Blocks {
   334  			for _, v := range b.Values {
   335  				changed = visit(v) || changed
   336  			}
   337  			
   338  			for _, c := range b.ControlValues() {
   339  				if n, ok := addr[c]; ok && !used.Has(n) {
   340  					used.Add(n)
   341  					changed = true
   342  				}
   343  			}
   344  		}
   345  		if !changed {
   346  			break
   347  		}
   348  	}
   349  
   350  	
   351  	for v, n := range elim {
   352  		if used.Has(n) {
   353  			continue
   354  		}
   355  		
   356  		v.SetArgs1(v.MemoryArg())
   357  		v.Aux = nil
   358  		v.AuxInt = 0
   359  		v.Op = OpCopy
   360  	}
   361  }
   362  
   363  
   364  
   365  func elimUnreadAutos(f *Func) {
   366  	
   367  	
   368  	
   369  	var seen ir.NameSet
   370  	var stores []*Value
   371  	for _, b := range f.Blocks {
   372  		for _, v := range b.Values {
   373  			n, ok := v.Aux.(*ir.Name)
   374  			if !ok {
   375  				continue
   376  			}
   377  			if n.Class != ir.PAUTO {
   378  				continue
   379  			}
   380  
   381  			effect := v.Op.SymEffect()
   382  			switch effect {
   383  			case SymNone, SymWrite:
   384  				
   385  				
   386  				
   387  				if !seen.Has(n) {
   388  					stores = append(stores, v)
   389  				}
   390  			default:
   391  				
   392  				
   393  				
   394  				
   395  				
   396  				if v.Uses > 0 {
   397  					seen.Add(n)
   398  				}
   399  			}
   400  		}
   401  	}
   402  
   403  	
   404  	for _, store := range stores {
   405  		n, _ := store.Aux.(*ir.Name)
   406  		if seen.Has(n) {
   407  			continue
   408  		}
   409  
   410  		
   411  		store.SetArgs1(store.MemoryArg())
   412  		store.Aux = nil
   413  		store.AuxInt = 0
   414  		store.Op = OpCopy
   415  	}
   416  }
   417  
View as plain text