Golang compiler optimization when covert bool to int

In golang, you can’t directly compare bool value and int value, and you can’t print bool value as digit 1 or 0 using fmt.Printf(). the best way is to convert bool variable to int.

How to do that? A most common way is to write a conversion function like this one.

func Bool2int(b bool) int {
	if b {
		return 1
	return 0

Which is quite easy to understand, but after searching in golang source codebase, I found this snippet.

func Bool2int(b bool) int {
	// The compiler currently only optimizes this form.
	// See issue 6011.
	var i int
	if b {
		i = 1
	} else {
		i = 0
	return i

It said that if we write code in this format, go compiler will help us optimize the assembly code.

Let’s see the assembly code after compilation.

➜  go build -gcflags='-l' test.go
➜  lldb test
(lldb) target create "test"
Current executable set to 'test' (x86_64).
(lldb) dis -n Bool2int1
test[0x109a080] <+0>:  movzbl 0x8(%rsp), %eax
test[0x109a085] <+5>:  testb  %al, %al
test[0x109a087] <+7>:  je     0x109a093                 ; <+19> at test.go:14
test[0x109a089] <+9>:  movq   $0x1, 0x10(%rsp)
test[0x109a092] <+18>: retq
test[0x109a093] <+19>: movq   $0x0, 0x10(%rsp)
test[0x109a09c] <+28>: retq

(lldb) dis -n Bool2int2
test[0x109a0a0] <+0>:  movzbl 0x8(%rsp), %eax
test[0x109a0a5] <+5>:  movzbl %al, %eax
test[0x109a0a8] <+8>:  movq   %rax, 0x10(%rsp)
test[0x109a0ad] <+13>: retq

You can see from the assembly, in usual way there is a comparision instruction, if true it’ll jump to another instruction and return 0 or 1, which is the same flow of our code. The second function is the assembly after optimization which has no jump instruction, instead it uses movzbl instruction.

MOVZ Instruction

Purpose: To convert an unsigned integer to a wider unsigned integer For MOVZBL, the low 8 bits of the destination are replaced by the source operand. the top 24 bits are set to 0. The source operand is unaffected.

if b == 1 then copy 8bits b to 32bits register and set higher 24 bits to 0,

0x01 => 0x00000001 
0x00 => 0x00000000

and return this register directly. So don’t need any comparision and jump instruction.

comments powered by Disqus