github.com/bir3/gocompiler@v0.9.2202/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  		for i, v := range b.ControlValues() {
    21  			if v.Op == OpCopy {
    22  				b.ReplaceControl(i, v.Args[0])
    23  			}
    24  		}
    25  	}
    26  
    27  	// Update named values.
    28  	for _, name := range f.Names {
    29  		values := f.NamedValues[*name]
    30  		for i, v := range values {
    31  			if v.Op == OpCopy {
    32  				values[i] = v.Args[0]
    33  			}
    34  		}
    35  	}
    36  }
    37  
    38  // copySource returns the (non-copy) op which is the
    39  // ultimate source of v.  v must be a copy op.
    40  func copySource(v *Value) *Value {
    41  	w := v.Args[0]
    42  
    43  	// This loop is just:
    44  	// for w.Op == OpCopy {
    45  	//     w = w.Args[0]
    46  	// }
    47  	// but we take some extra care to make sure we
    48  	// don't get stuck in an infinite loop.
    49  	// Infinite copy loops may happen in unreachable code.
    50  	// (TODO: or can they? Needs a test.)
    51  	slow := w
    52  	var advance bool
    53  	for w.Op == OpCopy {
    54  		w = w.Args[0]
    55  		if w == slow {
    56  			w.reset(OpUnknown)
    57  			break
    58  		}
    59  		if advance {
    60  			slow = slow.Args[0]
    61  		}
    62  		advance = !advance
    63  	}
    64  
    65  	// The answer is w.  Update all the copies we saw
    66  	// to point directly to w.  Doing this update makes
    67  	// sure that we don't end up doing O(n^2) work
    68  	// for a chain of n copies.
    69  	for v != w {
    70  		x := v.Args[0]
    71  		v.SetArg(0, w)
    72  		v = x
    73  	}
    74  	return w
    75  }
    76  
    77  // copyelimValue ensures that no args of v are copies.
    78  func copyelimValue(v *Value) {
    79  	for i, a := range v.Args {
    80  		if a.Op == OpCopy {
    81  			v.SetArg(i, copySource(a))
    82  		}
    83  	}
    84  }