diff options
Diffstat (limited to 'src/cmd/compile/internal/ssa/phielim.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/phielim.go | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go new file mode 100644 index 0000000..4fc9423 --- /dev/null +++ b/src/cmd/compile/internal/ssa/phielim.go @@ -0,0 +1,75 @@ +// 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 +} |