// 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 }