diff options
author | Alexandru Moșoi <mosoi@google.com> | 2016-04-12 18:24:34 +0200 |
---|---|---|
committer | Alexandru Moșoi <alexandru@mosoi.ro> | 2016-04-19 22:04:30 +0000 |
commit | 8b20fd000d7e894865442134f9d6d197ac5dabed (patch) | |
tree | 29c90352d4da834de0b9c12bcdb3d5e31fdd8652 /src/cmd/compile/internal/ssa/phiopt.go | |
parent | 082f464823cdb47042a142802776fa7874e6c05b (diff) | |
download | go-8b20fd000d7e894865442134f9d6d197ac5dabed.tar.gz go-8b20fd000d7e894865442134f9d6d197ac5dabed.zip |
cmd/compile: transform some Phis into Or8.
func f(a, b bool) bool {
return a || b
}
is now a single instructions (excluding loading and unloading the arguments):
v10 = ORB <bool> v11 v12 : AX
Change-Id: Iff63399410cb46909f4318ea1c3f45a029f4aa5e
Reviewed-on: https://go-review.googlesource.com/21872
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/ssa/phiopt.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/phiopt.go | 57 |
1 files changed, 32 insertions, 25 deletions
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go index 2d0a45733a..4efd497bdb 100644 --- a/src/cmd/compile/internal/ssa/phiopt.go +++ b/src/cmd/compile/internal/ssa/phiopt.go @@ -45,44 +45,51 @@ func phiopt(f *Func) { } // b0 is the if block giving the boolean value. - var reverse bool + // reverse is the predecessor from which the truth value comes. + var reverse int if b0.Succs[0] == pb0 && b0.Succs[1] == pb1 { - reverse = false + reverse = 0 } else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 { - reverse = true + reverse = 1 } else { b.Fatalf("invalid predecessors\n") } for _, v := range b.Values { - if v.Op != OpPhi || !v.Type.IsBoolean() || v.Args[0].Op != OpConstBool || v.Args[1].Op != OpConstBool { + if v.Op != OpPhi || !v.Type.IsBoolean() { continue } - ok, isCopy := false, false - if v.Args[0].AuxInt == 1 && v.Args[1].AuxInt == 0 { - ok, isCopy = true, !reverse - } else if v.Args[0].AuxInt == 0 && v.Args[1].AuxInt == 1 { - ok, isCopy = true, reverse - } - - // (Phi (ConstBool [x]) (ConstBool [x])) is already handled by opt / phielim. - - if ok && isCopy { - if f.pass.debug > 0 { - f.Config.Warnl(b.Line, "converted OpPhi to OpCopy") + // Replaces + // if a { x = true } else { x = false } with x = a + // and + // if a { x = false } else { x = true } with x = !a + if v.Args[0].Op == OpConstBool && v.Args[1].Op == OpConstBool { + if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt { + ops := [2]Op{OpNot, OpCopy} + v.reset(ops[v.Args[reverse].AuxInt]) + v.AddArg(b0.Control) + if f.pass.debug > 0 { + f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op) + } + continue } - v.reset(OpCopy) - v.AddArg(b0.Control) - continue } - if ok && !isCopy { - if f.pass.debug > 0 { - f.Config.Warnl(b.Line, "converted OpPhi to OpNot") + + // Replaces + // if a { x = true } else { x = value } with x = a || value. + // Requires that value dominates x, meaning that regardless of a, + // value is always computed. This guarantees that the side effects + // of value are not seen if a is false. + if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 { + if tmp := v.Args[1-reverse]; f.sdom.isAncestorEq(tmp.Block, b) { + v.reset(OpOr8) + v.SetArgs2(b0.Control, tmp) + if f.pass.debug > 0 { + f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op) + } + continue } - v.reset(OpNot) - v.AddArg(b0.Control) - continue } } } |