From e85265e8c2a41e4a0e703e5fb6fe762cc382d0af Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 2 May 2016 16:16:46 -0700 Subject: [PATCH] cmd/compile: optimize bool to int conversion MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This CL teaches SSA to recognize code of the form // b is a boolean value, i is an int of some flavor if b { i = 1 } else { i = 0 } and use b's underlying 0/1 representation for i instead of generating jumps. Unfortunately, it does not work on the obvious code: func bool2int(b bool) int { if b { return 1 } return 0 } This is left for future work. Note that the existing phiopt optimizations also don't work for: func neg(b bool) bool { if b { return false } return true } In the meantime, runtime authors and the like can use: func bool2int(b bool) int { var i int if b { i = 1 } else { i = 0 } return i } This compiles to: "".bool2int t=1 size=16 args=0x10 locals=0x0 0x0000 00000 (x.go:25) TEXT "".bool2int(SB), $0-16 0x0000 00000 (x.go:25) FUNCDATA $0, gclocals·23e8278e2b69a3a75fa59b23c49ed6ad(SB) 0x0000 00000 (x.go:25) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (x.go:32) MOVBLZX "".b+8(FP), AX 0x0005 00005 (x.go:32) MOVBQZX AL, AX 0x0008 00008 (x.go:32) MOVQ AX, "".~r1+16(FP) 0x000d 00013 (x.go:32) RET The extraneous MOVBQZX is #15300. This optimization also helps range and slice. The compiler must protect against pointers pointing to the end of a slice/string. It does this by increasing a pointer by either 0 or 1 * elemsize, based on a condition. This CL optimizes away a jump in that code. This CL triggers 382 times while compiling the standard library. Updating code to utilize this optimization is left for future CLs. Updates #6011 Change-Id: Ia7c1185f8aa223c543f91a3cd6d4a2a09c691c70 Reviewed-on: https://go-review.googlesource.com/22711 Run-TryBot: Josh Bleecher Snyder TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/phiopt.go | 61 +++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go index d6272b4cfc..fd40eb593e 100644 --- a/src/cmd/compile/internal/ssa/phiopt.go +++ b/src/cmd/compile/internal/ssa/phiopt.go @@ -57,7 +57,16 @@ func phiopt(f *Func) { } for _, v := range b.Values { - if v.Op != OpPhi || !v.Type.IsBoolean() { + if v.Op != OpPhi { + continue + } + + // Look for conversions from bool to 0/1. + if v.Type.IsInteger() { + phioptint(v, b0, reverse) + } + + if !v.Type.IsBoolean() { continue } @@ -110,5 +119,55 @@ func phiopt(f *Func) { } } } +} + +func phioptint(v *Value, b0 *Block, reverse int) { + a0 := v.Args[0] + a1 := v.Args[1] + if a0.Op != a1.Op { + return + } + + switch a0.Op { + case OpConst8, OpConst16, OpConst32, OpConst64: + default: + return + } + negate := false + switch { + case a0.AuxInt == 0 && a1.AuxInt == 1: + negate = true + case a0.AuxInt == 1 && a1.AuxInt == 0: + default: + return + } + + if reverse == 1 { + negate = !negate + } + + switch v.Type.Size() { + case 1: + v.reset(OpCopy) + case 2: + v.reset(OpZeroExt8to16) + case 4: + v.reset(OpZeroExt8to32) + case 8: + v.reset(OpZeroExt8to64) + default: + v.Fatalf("bad int size %d", v.Type.Size()) + } + + a := b0.Control + if negate { + a = v.Block.NewValue1(v.Line, OpNot, a.Type, a) + } + v.AddArg(a) + + f := b0.Func + if f.pass.debug > 0 { + f.Config.Warnl(v.Block.Line, "converted OpPhi bool -> int%d", v.Type.Size()*8) + } } -- 2.48.1