github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/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 // v = phi(x,x,x) 12 // v = phi(x,v,x,v) 13 // We repeat this process to also catch situations like: 14 // v = phi(x, phi(x, x), phi(x, v)) 15 // TODO: Can we also simplify cases like: 16 // v = phi(v, w, x) 17 // w = phi(v, w, x) 18 // and would that be useful? 19 func phielim(f *Func) { 20 for { 21 change := false 22 for _, b := range f.Blocks { 23 for _, v := range b.Values { 24 copyelimValue(v) 25 change = phielimValue(v) || change 26 } 27 } 28 if !change { 29 break 30 } 31 } 32 } 33 34 func phielimValue(v *Value) bool { 35 if v.Op != OpPhi { 36 return false 37 } 38 39 // If there are two distinct args of v which 40 // are not v itself, then the phi must remain. 41 // Otherwise, we can replace it with a copy. 42 var w *Value 43 for i, x := range v.Args { 44 if b := v.Block.Preds[i]; b.Kind == BlockFirst && b.Succs[1] == v.Block { 45 // This branch is never taken so we can just eliminate it. 46 continue 47 } 48 if x == v { 49 continue 50 } 51 if x == w { 52 continue 53 } 54 if w != nil { 55 return false 56 } 57 w = x 58 } 59 60 if w == nil { 61 // v references only itself. It must be in 62 // a dead code loop. Don't bother modifying it. 63 return false 64 } 65 v.Op = OpCopy 66 v.SetArgs1(w) 67 f := v.Block.Func 68 if f.pass.debug > 0 { 69 f.Config.Warnl(v.Line, "eliminated phi") 70 } 71 return true 72 }