Commit 8b20fd00 authored by Alexandru Moșoi's avatar Alexandru Moșoi Committed by Alexandru Moșoi

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: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 082f4648
...@@ -289,8 +289,9 @@ var passOrder = [...]constraint{ ...@@ -289,8 +289,9 @@ var passOrder = [...]constraint{
{"opt", "nilcheckelim"}, {"opt", "nilcheckelim"},
// tighten should happen before lowering to avoid splitting naturally paired instructions such as CMP/SET // tighten should happen before lowering to avoid splitting naturally paired instructions such as CMP/SET
{"tighten", "lower"}, {"tighten", "lower"},
// cse, nilcheckelim, prove and loopbce share idom. // cse, phiopt, nilcheckelim, prove and loopbce share idom.
{"generic domtree", "generic cse"}, {"generic domtree", "generic cse"},
{"generic domtree", "phiopt"},
{"generic domtree", "nilcheckelim"}, {"generic domtree", "nilcheckelim"},
{"generic domtree", "prove"}, {"generic domtree", "prove"},
{"generic domtree", "loopbce"}, {"generic domtree", "loopbce"},
......
...@@ -45,46 +45,53 @@ func phiopt(f *Func) { ...@@ -45,46 +45,53 @@ func phiopt(f *Func) {
} }
// b0 is the if block giving the boolean value. // 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 { if b0.Succs[0] == pb0 && b0.Succs[1] == pb1 {
reverse = false reverse = 0
} else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 { } else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 {
reverse = true reverse = 1
} else { } else {
b.Fatalf("invalid predecessors\n") b.Fatalf("invalid predecessors\n")
} }
for _, v := range b.Values { 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 continue
} }
ok, isCopy := false, false // Replaces
if v.Args[0].AuxInt == 1 && v.Args[1].AuxInt == 0 { // if a { x = true } else { x = false } with x = a
ok, isCopy = true, !reverse // and
} else if v.Args[0].AuxInt == 0 && v.Args[1].AuxInt == 1 { // if a { x = false } else { x = true } with x = !a
ok, isCopy = true, reverse 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}
// (Phi (ConstBool [x]) (ConstBool [x])) is already handled by opt / phielim. v.reset(ops[v.Args[reverse].AuxInt])
v.AddArg(b0.Control)
if ok && isCopy {
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to OpCopy") f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
} }
v.reset(OpCopy)
v.AddArg(b0.Control)
continue continue
} }
if ok && !isCopy { }
// 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 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to OpNot") f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
} }
v.reset(OpNot)
v.AddArg(b0.Control)
continue continue
} }
} }
} }
}
} }
// +build amd64 // +build amd64
// errorcheck -0 -d=ssa/phiopt/debug=3 // errorcheck -0 -d=ssa/phiopt/debug=3
// Copyright 2016 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 main package main
//go:noinline
func f0(a bool) bool { func f0(a bool) bool {
x := false x := false
if a { if a {
...@@ -10,9 +15,10 @@ func f0(a bool) bool { ...@@ -10,9 +15,10 @@ func f0(a bool) bool {
} else { } else {
x = false x = false
} }
return x // ERROR "converted OpPhi to OpCopy$" return x // ERROR "converted OpPhi to Copy$"
} }
//go:noinline
func f1(a bool) bool { func f1(a bool) bool {
x := false x := false
if a { if a {
...@@ -20,23 +26,49 @@ func f1(a bool) bool { ...@@ -20,23 +26,49 @@ func f1(a bool) bool {
} else { } else {
x = true x = true
} }
return x // ERROR "converted OpPhi to OpNot$" return x // ERROR "converted OpPhi to Not$"
} }
//go:noinline
func f2(a, b int) bool { func f2(a, b int) bool {
x := true x := true
if a == b { if a == b {
x = false x = false
} }
return x // ERROR "converted OpPhi to OpNot$" return x // ERROR "converted OpPhi to Not$"
} }
//go:noinline
func f3(a, b int) bool { func f3(a, b int) bool {
x := false x := false
if a == b { if a == b {
x = true x = true
} }
return x // ERROR "converted OpPhi to OpCopy$" return x // ERROR "converted OpPhi to Copy$"
}
//go:noinline
func f4(a, b bool) bool {
return a || b // ERROR "converted OpPhi to Or8$"
}
//go:noinline
func f5(a int, b bool) bool {
x := b
if a == 0 {
x = true
}
return x // ERROR "converted OpPhi to Or8$"
}
//go:noinline
func f6(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)
}
return x
} }
func main() { func main() {
......
// +build amd64 // +build amd64
// errorcheck -0 -d=ssa/prove/debug=3 // errorcheck -0 -d=ssa/prove/debug=3
// Copyright 2016 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 main package main
import "math" import "math"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment