mirror of
https://github.com/golang/go
synced 2024-11-26 15:36:59 -07:00
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>
This commit is contained in:
parent
082f464823
commit
8b20fd000d
@ -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) {
|
|||||||
}
|
}
|
||||||
// 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])
|
||||||
|
|
||||||
if ok && isCopy {
|
|
||||||
if f.pass.debug > 0 {
|
|
||||||
f.Config.Warnl(b.Line, "converted OpPhi to OpCopy")
|
|
||||||
}
|
|
||||||
v.reset(OpCopy)
|
|
||||||
v.AddArg(b0.Control)
|
v.AddArg(b0.Control)
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ok && !isCopy {
|
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
// +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 {
|
|||||||
} 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 {
|
|||||||
} 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() {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
// +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"
|
||||||
|
Loading…
Reference in New Issue
Block a user