mirror of
https://github.com/golang/go
synced 2024-11-11 19:41:36 -07:00
[dev.ssa] cmd/compile/internal/ssa: simplify boolean phis
* Decreases the generated code slightly. * Similar to phiopt pass from gcc, except it only handles booleans. Handling Eq/Neq had no impact on the generated code. name old time/op new time/op delta Template 453ms ± 4% 451ms ± 4% ~ (p=0.468 n=24+24) GoTypes 1.55s ± 1% 1.55s ± 2% ~ (p=0.287 n=24+25) Compiler 6.53s ± 2% 6.56s ± 1% +0.46% (p=0.050 n=23+23) MakeBash 45.8s ± 2% 45.7s ± 2% ~ (p=0.866 n=24+25) name old text-bytes new text-bytes delta HelloSize 676k ± 0% 676k ± 0% ~ (all samples are equal) CmdGoSize 8.07M ± 0% 8.07M ± 0% -0.03% (p=0.000 n=25+25) Change-Id: Ia62477b7554127958a14cb27f85849b095d63663 Reviewed-on: https://go-review.googlesource.com/20090 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Alexandru Moșoi <alexandru@mosoi.ro> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
1f6e9e36b0
commit
e197f467d5
@ -164,6 +164,7 @@ var passes = [...]pass{
|
||||
{name: "zero arg cse", fn: zcse, required: true}, // required to merge OpSB values
|
||||
{name: "opt deadcode", fn: deadcode}, // remove any blocks orphaned during opt
|
||||
{name: "generic cse", fn: cse},
|
||||
{name: "phiopt", fn: phiopt},
|
||||
{name: "nilcheckelim", fn: nilcheckelim},
|
||||
{name: "prove", fn: prove},
|
||||
{name: "generic deadcode", fn: deadcode},
|
||||
|
86
src/cmd/compile/internal/ssa/phiopt.go
Normal file
86
src/cmd/compile/internal/ssa/phiopt.go
Normal file
@ -0,0 +1,86 @@
|
||||
package ssa
|
||||
|
||||
// phiopt eliminates boolean Phis based on the previous if.
|
||||
//
|
||||
// Main use case is to transform:
|
||||
// x := false
|
||||
// if b {
|
||||
// x = true
|
||||
// }
|
||||
// into x = b.
|
||||
//
|
||||
// In SSA code this appears as
|
||||
//
|
||||
// b0
|
||||
// If b -> b1 b2
|
||||
// b1
|
||||
// Plain -> b2
|
||||
// b2
|
||||
// x = (OpPhi (ConstBool [true]) (ConstBool [false]))
|
||||
//
|
||||
// In this case we can replace x with a copy of b.
|
||||
func phiopt(f *Func) {
|
||||
for _, b := range f.Blocks {
|
||||
if len(b.Preds) != 2 || len(b.Values) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
pb0, b0 := b, b.Preds[0]
|
||||
for b0.Kind != BlockIf && len(b0.Preds) == 1 {
|
||||
pb0, b0 = b0, b0.Preds[0]
|
||||
}
|
||||
if b0.Kind != BlockIf {
|
||||
continue
|
||||
}
|
||||
pb1, b1 := b, b.Preds[1]
|
||||
for b1.Kind != BlockIf && len(b1.Preds) == 1 {
|
||||
pb1, b1 = b1, b1.Preds[0]
|
||||
}
|
||||
if b1 != b0 {
|
||||
continue
|
||||
}
|
||||
// b0 is the if block giving the boolean value.
|
||||
|
||||
var reverse bool
|
||||
if b0.Succs[0] == pb0 && b0.Succs[1] == pb1 {
|
||||
reverse = false
|
||||
} else if b0.Succs[0] == pb1 && b0.Succs[1] == pb0 {
|
||||
reverse = true
|
||||
} 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 {
|
||||
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(int(b.Line), "converted OpPhi to OpCopy")
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.AddArg(b0.Control)
|
||||
continue
|
||||
}
|
||||
if ok && !isCopy {
|
||||
if f.pass.debug > 0 {
|
||||
f.Config.Warnl(int(b.Line), "converted OpPhi to OpNot")
|
||||
}
|
||||
v.reset(OpNot)
|
||||
v.AddArg(b0.Control)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
43
test/phiopt.go
Normal file
43
test/phiopt.go
Normal file
@ -0,0 +1,43 @@
|
||||
// +build amd64
|
||||
// errorcheck -0 -d=ssa/phiopt/debug=3
|
||||
|
||||
package main
|
||||
|
||||
func f0(a bool) bool {
|
||||
x := false
|
||||
if a {
|
||||
x = true
|
||||
} else {
|
||||
x = false
|
||||
}
|
||||
return x // ERROR "converted OpPhi to OpCopy$"
|
||||
}
|
||||
|
||||
func f1(a bool) bool {
|
||||
x := false
|
||||
if a {
|
||||
x = false
|
||||
} else {
|
||||
x = true
|
||||
}
|
||||
return x // ERROR "converted OpPhi to OpNot$"
|
||||
}
|
||||
|
||||
func f2(a, b int) bool {
|
||||
x := true
|
||||
if a == b {
|
||||
x = false
|
||||
}
|
||||
return x // ERROR "converted OpPhi to OpNot$"
|
||||
}
|
||||
|
||||
func f3(a, b int) bool {
|
||||
x := false
|
||||
if a == b {
|
||||
x = true
|
||||
}
|
||||
return x // ERROR "converted OpPhi to OpCopy$"
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user