go ``` cmd/compile: 优化未对齐的加载-XOR-存储在字节片段上 ```

au9on6nz  于 6个月前  发布在  Go
关注(0)|答案(3)|浏览(47)

如果以下代码在支持无对齐加载/存储的平台上是等价的(386, amd64, arm64, ppc64le, s390x...),那就太好了。我在这些例子中使用了XOR,但对于其他逻辑运算符也是如此:
(1)

binary.LittleEndian.PutUint32(dst, binary.LittleEndian.Uint32(src) ^ x)

(2)

dst[0] = src[0] ^ byte(x)
dst[1] = src[1] ^ byte(x>>8)
dst[2] = src[2] ^ byte(x>>16)
dst[3] = src[3] ^ byte(x>>24)

(3) [不太重要]

x ^= uint32(src[0])
x ^= uint32(src[1]) << 8
x ^= uint32(src[2]) << 16
x ^= uint32(src[3]) << 24
binary.LittleEndian.PutUint32(dst, x)

目前(1)在具有无对齐加载的平台上是最优的,而(2)在其他平台上是最优的。如果编译器能将(2)优化为(1),那就太好了。我将(3)作为当前规则次优的情况添加进来。
如果这样做了,它将有助于简化通用的 golang.org/x/crypto/internal/chacha20 实现。

eimct9ow

eimct9ow1#

我认为我遗漏了一些东西:为什么(1)在其他平台上不是最优的?

uplii1fm

uplii1fm2#

示例(1)等同于以下包含额外3个移位的代码:

v := uint32(src[0])
v |= uint32(src[1]) << 8
v |= uint32(src[2]) << 16
v |= uint32(src[3]) << 24
v ^= u
dst[0] = byte(v)
dst[1] = byte(v>>8)
dst[2] = byte(v>>16)
dst[3] = byte(v>>24)

另一方面,由于移位寄存器输入,这实际上在arm上并不会产生更多的指令。尽管如此,mips上的汇编语言从(2)中受益更多。我不知道是否存在速度差异。

dnph8jn4

dnph8jn43#

看起来(1)是我们期望人们写的代码,它可能比(2)更容易识别和重写。(通常,数学运算的分发比取消分发更容易,尤其是不带传递性的二进制运算。)

相关问题