|  | // Copyright 2015 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package ssa | 
|  |  | 
|  | // phielim eliminates redundant phi values from f. | 
|  | // A phi is redundant if its arguments are all equal. For | 
|  | // purposes of counting, ignore the phi itself. Both of | 
|  | // these phis are redundant: | 
|  | //   v = phi(x,x,x) | 
|  | //   v = phi(x,v,x,v) | 
|  | // We repeat this process to also catch situations like: | 
|  | //   v = phi(x, phi(x, x), phi(x, v)) | 
|  | // TODO: Can we also simplify cases like: | 
|  | //   v = phi(v, w, x) | 
|  | //   w = phi(v, w, x) | 
|  | // and would that be useful? | 
|  | func phielim(f *Func) { | 
|  | for { | 
|  | change := false | 
|  | for _, b := range f.Blocks { | 
|  | for _, v := range b.Values { | 
|  | copyelimValue(v) | 
|  | change = phielimValue(v) || change | 
|  | } | 
|  | } | 
|  | if !change { | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // phielimValue tries to convert the phi v to a copy. | 
|  | func phielimValue(v *Value) bool { | 
|  | if v.Op != OpPhi { | 
|  | return false | 
|  | } | 
|  |  | 
|  | // If there are two distinct args of v which | 
|  | // are not v itself, then the phi must remain. | 
|  | // Otherwise, we can replace it with a copy. | 
|  | var w *Value | 
|  | for _, x := range v.Args { | 
|  | if x == v { | 
|  | continue | 
|  | } | 
|  | if x == w { | 
|  | continue | 
|  | } | 
|  | if w != nil { | 
|  | return false | 
|  | } | 
|  | w = x | 
|  | } | 
|  |  | 
|  | if w == nil { | 
|  | // v references only itself. It must be in | 
|  | // a dead code loop. Don't bother modifying it. | 
|  | return false | 
|  | } | 
|  | v.Op = OpCopy | 
|  | v.SetArgs1(w) | 
|  | f := v.Block.Func | 
|  | if f.pass.debug > 0 { | 
|  | f.Warnl(v.Pos, "eliminated phi") | 
|  | } | 
|  | return true | 
|  | } |