github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ssa/copyelim.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  // 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  }