Proposal Details
tldr: extend phiopt with
// if a { x = c } else { x = 0 } with x = (-bool2int(a)) & c
// if a { x |= c } with x = x | ((-bool2int(a)) & c)
// if a { x ^= c } with x = x ^ ((-bool2int(a)) & c)
// if a { x += c } with x = x + ((-bool2int(a)) & c)
i was working on writing code that packed booleans into a uint16, and realised that i could not use bitwise operations to do this, and found this discussed in #9367 #64825
the response is that one should write something like
func bool2int(b bool) int {
x := 0
if b {
x = 1
}
return x
}
which does properly get optimized to MOVBLZX
however, when writing code like
func packBool(a, b, c, d, e bool) (t uint16) {
if a { t |= 1 << 0 }
if b { t |= 1 << 1 }
if c { t |= 1 << 2 }
if d { t |= 1 << 3 }
if e { t |= 1 << 5 }
return
}
it is unable to get code that is as fast as using bitwise ops, see here: https://godbolt.org/z/aGY6Pbdob we see that it is a chain of TEST+CMOV, which is much slower than the shifts. (40% difference in performance on my machine)
instead of allowing the bool cast, i would like to propose that the go compiler should also be able to optimize for this use case.
right now, the existing phiopt https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/phiopt.go#L288 is only able to handle the case of constant pairs that are 0 and 1.
i would like to propose we add these two optimizations that should make this optimization possible
first, we i propose we allow the optimization of
var x uint32
if conf {
x = 0xff
}
which is a TESTB+CMOV to
mask := -bool2int(cond)
x = mask ^ 0xFF
which is a NEGL+ANGL
second, i propose we allow the optimization of multiple Or/Xor/And into accumulator. for instance.
var x uint32
if a { x |= 1 }
if b { x |= 2 }
if c { x |= 4 }
to something like
x = bool2int(a)
x = x | (-bool2int(b) & 2)
x = x | (-bool2int(c) & 4)
with similar transformations which can also be done for xor and add-
x = x ^ ((-bool2int(a)) & c)
x = x + ((-bool2int(a)) & c)
i've tried to play around with doing this in this pr to my fork here: https://github.com/elee1766/go/pull/1/changes
and it seems to be able to produce the correct machine code.
Proposal Details
tldr: extend phiopt with
i was working on writing code that packed booleans into a uint16, and realised that i could not use bitwise operations to do this, and found this discussed in #9367 #64825
the response is that one should write something like
which does properly get optimized to MOVBLZX
however, when writing code like
it is unable to get code that is as fast as using bitwise ops, see here: https://godbolt.org/z/aGY6Pbdob we see that it is a chain of TEST+CMOV, which is much slower than the shifts. (40% difference in performance on my machine)
instead of allowing the bool cast, i would like to propose that the go compiler should also be able to optimize for this use case.
right now, the existing phiopt https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/phiopt.go#L288 is only able to handle the case of constant pairs that are 0 and 1.
i would like to propose we add these two optimizations that should make this optimization possible
first, we i propose we allow the optimization of
which is a
TESTB+CMOVtowhich is a
NEGL+ANGLsecond, i propose we allow the optimization of multiple Or/Xor/And into accumulator. for instance.
to something like
with similar transformations which can also be done for xor and add-
i've tried to play around with doing this in this pr to my fork here: https://github.com/elee1766/go/pull/1/changes
and it seems to be able to produce the correct machine code.