github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ssa/phielim.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  // phielim eliminates redundant phi values from f.
     8  // A phi is redundant if its arguments are all equal. For
     9  // purposes of counting, ignore the phi itself. Both of
    10  // these phis are redundant:
    11  //
    12  //	v = phi(x,x,x)
    13  //	v = phi(x,v,x,v)
    14  //
    15  // We repeat this process to also catch situations like:
    16  //
    17  //	v = phi(x, phi(x, x), phi(x, v))
    18  //
    19  // TODO: Can we also simplify cases like:
    20  //
    21  //	v = phi(v, w, x)
    22  //	w = phi(v, w, x)
    23  //
    24  // and would that be useful?
    25  func phielim(f *Func) {
    26  	for {
    27  		change := false
    28  		for _, b := range f.Blocks {
    29  			for _, v := range b.Values {
    30  				copyelimValue(v)
    31  				change = phielimValue(v) || change
    32  			}
    33  		}
    34  		if !change {
    35  			break
    36  		}
    37  	}
    38  }
    39  
    40  // phielimValue tries to convert the phi v to a copy.
    41  func phielimValue(v *Value) bool {
    42  	if v.Op != OpPhi {
    43  		return false
    44  	}
    45  
    46  	// If there are two distinct args of v which
    47  	// are not v itself, then the phi must remain.
    48  	// Otherwise, we can replace it with a copy.
    49  	var w *Value
    50  	for _, x := range v.Args {
    51  		if x == v {
    52  			continue
    53  		}
    54  		if x == w {
    55  			continue
    56  		}
    57  		if w != nil {
    58  			return false
    59  		}
    60  		w = x
    61  	}
    62  
    63  	if w == nil {
    64  		// v references only itself. It must be in
    65  		// a dead code loop. Don't bother modifying it.
    66  		return false
    67  	}
    68  	v.Op = OpCopy
    69  	v.SetArgs1(w)
    70  	f := v.Block.Func
    71  	if f.pass.debug > 0 {
    72  		f.Warnl(v.Pos, "eliminated phi")
    73  	}
    74  	return true
    75  }