diff options
author | Alexandru Moșoi <mosoi@google.com> | 2016-02-29 19:29:04 +0100 |
---|---|---|
committer | Alexandru Moșoi <alexandru@mosoi.ro> | 2016-03-01 17:56:13 +0000 |
commit | e197f467d51318305439610d44af0e20dae7062f (patch) | |
tree | 5f68f19c7e102f4718e8fd7cea3fab8a7fa6ccd1 /src/cmd/compile/internal/ssa/phiopt.go | |
parent | 1f6e9e36b0aba3d2459c80b2c8e905d9cc57f7ce (diff) | |
download | go-e197f467d51318305439610d44af0e20dae7062f.tar.gz go-e197f467d51318305439610d44af0e20dae7062f.zip |
[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>
Diffstat (limited to 'src/cmd/compile/internal/ssa/phiopt.go')
-rw-r--r-- | src/cmd/compile/internal/ssa/phiopt.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go new file mode 100644 index 0000000000..fb17727242 --- /dev/null +++ b/src/cmd/compile/internal/ssa/phiopt.go @@ -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 + } + } + } + +} |