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
}
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
+ }
+ }
}
}
}
//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() {
}