Go编译器是否足够聪明以获得微优化?

时间:2015-04-30 19:19:51

标签: go

我很好奇使用像

这样的微优化是否有意义
    当li是整数时,
  • a / 2a >> 1对比
  • a * 2 vs a << 1
  • a % 2 vs a & 1
  • 以及其他一些

我知道任何体面的C编译器都可以处理这个问题。另外请不要写关于过早优化,因为这些技术是如此明显,甚至不是优化,更像是喜欢如何编写代码。

P.S。我试图做基准测试,时间上的差异在统计上并不显着。我不知道如何检查go的字节码,所以谢谢你的指点。

1 个答案:

答案 0 :(得分:10)

简短的回答,是的,编译器优化了这些。 但int vs uint(并且可能是任何有符号与无符号整数类型,例如byte)的情况略有不同。

在这两种情况下都可以避免乘法和除法指令,但它只是无符号整数的单个指令(以及有符号整数的少量指令)。 那是因为你的成对语句只对无符号整数完全等价而不是有符号整数。

更长的回答:

采取一个简单的程序,如:

package main

func main() {}

func div2(a int) {
        b := a / 2
        c := a >> 1
        _, _ = b, c
}

func mul2(a int) {
        b := a * 2
        c := a << 1
        _, _ = b, c
}

func mod2(a int) {
        b := a % 2
        c := a & 1
        _, _ = b, c
}

并且运行go build -gcflags="-S"将为您提供汇编输出,例如:

"".mod2 t=1 size=32 value=0 args=0x8 locals=0x0
        0x0000 00000 (…/opt.go:17)       TEXT    "".mod2+0(SB),4,$0-8
        …
        0x0000 00000 (…/opt.go:17)       MOVQ    "".a+8(FP),BX
        …
        0x0005 00005 (…/opt.go:18)       MOVQ    BX,AX
        0x0008 00008 (…/opt.go:18)       SARQ    $63,AX
        0x000c 00012 (…/opt.go:18)       MOVQ    BX,DX
        0x000f 00015 (…/opt.go:18)       SUBQ    AX,DX
        0x0012 00018 (…/opt.go:18)       ANDQ    $1,DX
        0x0016 00022 (…/opt.go:18)       ADDQ    AX,DX
        0x0019 00025 (…/opt.go:19)       ANDQ    $1,BX
        0x001d 00029 (…/opt.go:21)       RET     ,

此处BX是参数,DXBX似乎是两个结果 (BX被重用作其中一个结果)。 这里它们略有不同,但只有几条说明 (查看显示的源行号) 并且没有任何除法或乘法指令 (所以基本上一样快)。 差异是由于算法与逻辑的变化以及Go如何对负值进行模拟。

您可以通过在程序中将int更改为uint来确认,然后输出包含以下内容:

        0x0008 00008 (…/opt.go:18)       ANDQ    $1,CX
        0x000c 00012 (…/opt.go:19)       ANDQ    $1,BX

即。完全相同的指令。 对于您提供的每个示例都是如此。