]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: convert some Phis into And8.
authorAlexandru Moșoi <mosoi@google.com>
Fri, 22 Apr 2016 10:44:31 +0000 (12:44 +0200)
committerAlexandru Moșoi <alexandru@mosoi.ro>
Fri, 22 Apr 2016 17:22:03 +0000 (17:22 +0000)
See discussion at [1]. True value must have a fixed non-zero
representation meaning that a && b can be implemented as a & b.

[1] https://groups.google.com/forum/#!topic/golang-dev/xV0vPuFP9Vg

This change helps with m := a && b, but it's more common to see
if a && b { do something } which is not handled.

Change-Id: Ib6f9ff898a0a8c05d12466e2464e4fe781035394
Reviewed-on: https://go-review.googlesource.com/22313
Run-TryBot: Alexandru Moșoi <alexandru@mosoi.ro>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/phiopt.go
test/phiopt.go

index 4efd497bdb8525d065f6355455a0148c50867fa1..aae83bacf28d0fbbb68af79ba8d3eb90839ab104 100644 (file)
@@ -26,6 +26,7 @@ package ssa
 func phiopt(f *Func) {
        for _, b := range f.Blocks {
                if len(b.Preds) != 2 || len(b.Values) == 0 {
+                       // TODO: handle more than 2 predecessors, e.g. a || b || c.
                        continue
                }
 
@@ -91,6 +92,22 @@ func phiopt(f *Func) {
                                        continue
                                }
                        }
+
+                       // Replaces
+                       //   if a { x = value } else { x = false } 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[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
+                               if tmp := v.Args[reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+                                       v.reset(OpAnd8)
+                                       v.SetArgs2(b0.Control, tmp)
+                                       if f.pass.debug > 0 {
+                                               f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+                                       }
+                                       continue
+                               }
+                       }
                }
        }
 
index 37caab0b513cbc18ffd0aeb898a017e6d6c0559b..43479097524df104c3fcae7ca2430153d81709b3 100644 (file)
@@ -53,23 +53,56 @@ func f4(a, b bool) bool {
 }
 
 //go:noinline
-func f5(a int, b bool) bool {
-       x := b
+func f5or(a int, b bool) bool {
+       var x bool
        if a == 0 {
                x = true
+       } else {
+               x = b
        }
        return x // ERROR "converted OpPhi to Or8$"
 }
 
 //go:noinline
-func f6(a int, b bool) bool {
+func f5and(a int, b bool) bool {
+       var x bool
+       if a == 0 {
+               x = b
+       } else {
+               x = false
+       }
+       return x // ERROR "converted OpPhi to And8$"
+}
+
+//go:noinline
+func f6or(a int, b bool) bool {
        x := b
        if a == 0 {
-               // f6 has side effects so the OpPhi should not be converted.
-               x = f6(a, b)
+               // f6or has side effects so the OpPhi should not be converted.
+               x = f6or(a, b)
        }
        return x
 }
 
+//go:noinline
+func f6and(a int, b bool) bool {
+       x := b
+       if a == 0 {
+               // f6and has side effects so the OpPhi should not be converted.
+               x = f6and(a, b)
+       }
+       return x
+}
+
+//go:noinline
+func f7or(a bool, b bool) bool {
+       return a || b // ERROR "converted OpPhi to Or8$"
+}
+
+//go:noinline
+func f7and(a bool, b bool) bool {
+       return a && b // ERROR "converted OpPhi to And8$"
+}
+
 func main() {
 }