Skip to content

Commit e85265e

Browse files
committed
cmd/compile: optimize bool to int conversion
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent c7b9bd7 commit e85265e

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

src/cmd/compile/internal/ssa/phiopt.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,16 @@ func phiopt(f *Func) {
5757
}
5858

5959
for _, v := range b.Values {
60-
if v.Op != OpPhi || !v.Type.IsBoolean() {
60+
if v.Op != OpPhi {
61+
continue
62+
}
63+
64+
// Look for conversions from bool to 0/1.
65+
if v.Type.IsInteger() {
66+
phioptint(v, b0, reverse)
67+
}
68+
69+
if !v.Type.IsBoolean() {
6170
continue
6271
}
6372

@@ -110,5 +119,55 @@ func phiopt(f *Func) {
110119
}
111120
}
112121
}
122+
}
123+
124+
func phioptint(v *Value, b0 *Block, reverse int) {
125+
a0 := v.Args[0]
126+
a1 := v.Args[1]
127+
if a0.Op != a1.Op {
128+
return
129+
}
130+
131+
switch a0.Op {
132+
case OpConst8, OpConst16, OpConst32, OpConst64:
133+
default:
134+
return
135+
}
113136

137+
negate := false
138+
switch {
139+
case a0.AuxInt == 0 && a1.AuxInt == 1:
140+
negate = true
141+
case a0.AuxInt == 1 && a1.AuxInt == 0:
142+
default:
143+
return
144+
}
145+
146+
if reverse == 1 {
147+
negate = !negate
148+
}
149+
150+
switch v.Type.Size() {
151+
case 1:
152+
v.reset(OpCopy)
153+
case 2:
154+
v.reset(OpZeroExt8to16)
155+
case 4:
156+
v.reset(OpZeroExt8to32)
157+
case 8:
158+
v.reset(OpZeroExt8to64)
159+
default:
160+
v.Fatalf("bad int size %d", v.Type.Size())
161+
}
162+
163+
a := b0.Control
164+
if negate {
165+
a = v.Block.NewValue1(v.Line, OpNot, a.Type, a)
166+
}
167+
v.AddArg(a)
168+
169+
f := b0.Func
170+
if f.pass.debug > 0 {
171+
f.Config.Warnl(v.Block.Line, "converted OpPhi bool -> int%d", v.Type.Size()*8)
172+
}
114173
}

0 commit comments

Comments
 (0)