Go编译器是否足够智能以获得微优化?

Sal*_*ali -2 go

我很好奇使用微优化是否合理

  • a / 2a >> 1当a为整数
  • a * 2 VS a << 1
  • a % 2 VS a & 1
  • 和其他一些像这样的人

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

PS我尝试做基准测试,时间上的差异没有统计学意义.我不知道如何检查go的字节码,所以谢谢你的指点.

Dav*_*e C 10

简而言之,是的,编译器优化了这些.但是对于intvs 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
}
Run Code Online (Sandbox Code Playgroud)

并且运行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     ,
Run Code Online (Sandbox Code Playgroud)

BX是参数,DX并且BX似乎是两个结果(BX被重用作结果之一).这里它们略有不同,但只有几条指令(查看显示的源行号)并且没有任何除法或乘法指令(因此基本上同样快).差异是由于算法与逻辑转换以及Go如何对负值进行修改.

您可以通过更改intuint程序来确认这一点,然后输出包含以下内容:

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

即完全相同的指令.对于您给出的每个示例都是如此.

  • 这里需要注意的是,编译器可以正确识别可以进行优化的情况,例如无符号整数,以及避免无法完成的情况,例如有可能使符号位移位完全错误的有符号整数. (7认同)