Home | History | Annotate | Download | only in ssa
      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 // copyelim removes all uses of OpCopy values from f.
      8 // A subsequent deadcode pass is needed to actually remove the copies.
      9 func copyelim(f *Func) {
     10 	// Modify all values so no arg (including args
     11 	// of OpCopy) is a copy.
     12 	for _, b := range f.Blocks {
     13 		for _, v := range b.Values {
     14 			copyelimValue(v)
     15 		}
     16 	}
     17 
     18 	// Update block control values.
     19 	for _, b := range f.Blocks {
     20 		if v := b.Control; v != nil && v.Op == OpCopy {
     21 			b.SetControl(v.Args[0])
     22 		}
     23 	}
     24 
     25 	// Update named values.
     26 	for _, name := range f.Names {
     27 		values := f.NamedValues[name]
     28 		for i, v := range values {
     29 			if v.Op == OpCopy {
     30 				values[i] = v.Args[0]
     31 			}
     32 		}
     33 	}
     34 }
     35 
     36 // copySource returns the (non-copy) op which is the
     37 // ultimate source of v.  v must be a copy op.
     38 func copySource(v *Value) *Value {
     39 	w := v.Args[0]
     40 
     41 	// This loop is just:
     42 	// for w.Op == OpCopy {
     43 	//     w = w.Args[0]
     44 	// }
     45 	// but we take some extra care to make sure we
     46 	// don't get stuck in an infinite loop.
     47 	// Infinite copy loops may happen in unreachable code.
     48 	// (TODO: or can they?  Needs a test.)
     49 	slow := w
     50 	var advance bool
     51 	for w.Op == OpCopy {
     52 		w = w.Args[0]
     53 		if w == slow {
     54 			w.reset(OpUnknown)
     55 			break
     56 		}
     57 		if advance {
     58 			slow = slow.Args[0]
     59 		}
     60 		advance = !advance
     61 	}
     62 
     63 	// The answer is w.  Update all the copies we saw
     64 	// to point directly to w.  Doing this update makes
     65 	// sure that we don't end up doing O(n^2) work
     66 	// for a chain of n copies.
     67 	for v != w {
     68 		x := v.Args[0]
     69 		v.SetArg(0, w)
     70 		v = x
     71 	}
     72 	return w
     73 }
     74 
     75 // copyelimValue ensures that no args of v are copies.
     76 func copyelimValue(v *Value) {
     77 	for i, a := range v.Args {
     78 		if a.Op == OpCopy {
     79 			v.SetArg(i, copySource(a))
     80 		}
     81 	}
     82 }
     83